Scala基础03-OOP面向对象

一、类的创建方式

  • 和Java创建普通类的方式基本一样
  • 不同之处在于可以在类型之后添加参数,作为类的主构造器
  • 在类里定义this()方法重载构造器,作为辅助构造器(辅构造器的第一句必须为调用其他构造器)
package oop
 class Point(xc: Int,yc:Int){
  var x:Int=xc //成员变量
  var y:Int=yc
  //辅助构造器
  def this()={
    this(0,0) //
  }
  //成员方法
  def move(dx:Int,dy:Int)={
    x=x+dx
    y=y+dy
  }
  def width():Int=x
}
    var p1 = new Point(3,5)
    println(p1.width())
    println(p1.move(1, 2))
  • 简便的创建类方式
class Dog(val name:String,var age:Int){
  def cry()=println("wow...")
}
    var dog=new Dog("dahuang",2)

二、生成getter、setter方法

  • 添加@BooleanBeanProperty注解,即可调用类似java里的get set(is)方法
import scala.beans.BooleanBeanProperty
class Person(){
  @BooleanBeanProperty
  var name:String=""
  @BooleanBeanProperty
  var age:Int=0
  @BooleanBeanProperty
  var gender:String=""
  def this(name:String,age:Int,gender:String){
    this()
    this.name=name
    this.age=age
    this.gender=gender
  }
  override def toString: String = s"$name,$age,$gender"
}

object Testgettersetter {
  def main(args: Array[String]): Unit = {
    var p2 = new Person
    println(p2)
    p2 = new Person("henry",22,"male")
    println(p2)
    p2.setName("pola")
    p2.setAge(12)
    p2.setGender("female")
    println(p2)
  }
}

其他注解

@native 标注用c实现的本地方法
@throws(classOf[Exception]) def test() {} 给方法标记要抛出的checked异常
@varargs def test(args: String*) {} 标记方法接收的是变长参数
@BeanProperty 标记生成JavaBean风格的getter和setter方法
@BooleanBeanProperty 标记生成is风格的getter方法,用于boolean类型的field
@deprecated(message = "") 让编译器提示过期警告
@unchecked 让编译器提示类型转换的警告

三、类的继承

class BlackPoint()extends Point{
  private var color="black"
  override def move(dx: Int, dy: Int): Unit = {
    x= x+dx
    y=y+dy
    println(s"moved to x:$x y:$y")
  }
}
    var bp = new BlackPoint()
    bp.x=4
    bp.y=6
    bp.move(1,2)

四、抽象类

abstract  class Shape{
  def draw():Unit
}
class Square extends Shape{
  override def draw(): Unit = {
    println("draw a square")
  }
}
    var shape = new Square
    shape.draw()

五、单例对象

  • 使用“object”关键字声明,可包含变量、方法与代码定义
  • 单例对象中的成员变量、成员方法通过单例对象名直接调用
  • 单例对象第一次被访问时初始化,并执行全部代码块
  • 单例对象不能new,且无构造参数
  • 程序入口main()方法必须定义在单例对象中
  • 单例对象与同名类定义在同一文件中时形成绑定关系。
object Blah{
  println("Blah initializing...")
  def sum(l:List[Int]):Int=l.sum
}
	println(Blah.sum(List[Int](1, 2, 3, 4, 5, 6)))

六、伴生对象与伴生类

  • 单例对象与同名类定义在同一文件中时形成绑定关系
  • 伴生类与伴生对象可相互访问各自私有成员
  • 伴生对象可为伴生类增加静态成员
  • 在object中一般可以为伴生类做一些初始化等操作
class Student(n:String,a:Int){
  private var name = n
  private var age = a
}
object Student{
  def apply(n: String, a: Int): Student = new Student(n, a)
  def main(args: Array[String]): Unit = {
    val stu=Student("Jason",9) //通过伴生对象的apply()方法创建实例
    println(stu.name)
  }
}

七、特质

  • 特质使用“trait”关键字定义,而特质类似Java接口,不能被实例化,没有构造参数
  • 特质是字段和方法的集合,可以提供字段和方法实现
  • 类和单例对象都可以扩展特质(extends)
  • 实现特质中的方法使用“override”。
trait Pet{
  var name:String
  def cry():Unit
}
class Cat(var name:String) extends Pet{
  override def cry() = println("wow = = ")
}
    val cat = new Cat("henry")
    import scala.collection.mutable._
    val animals = ArrayBuffer.empty[Pet]
    animals.append(cat)
    animals.foreach(pet=>{
      println(pet.name)
      pet.cry()
    })

八、混合特质(mixin)

  • 当某个特质被用于组合类时,被称为混入
  • 一个类只能有一个父类但是可以有多个混入(第一个父类或特质用exteds,多混入with)。
  • 静态继承(混入),类似Java里的实现接口
  • 强制动态混入(self: ),在使用的时候必须调用
  • 随机动态混入,在使用的时候调用
abstract class A{
  val message:String
}
class B extends A{
  override val message: String = "I'm a instance of class B"
}
trait C extends A{
  def loudMessage = message.toUpperCase()
}
class D extends B with C
    val d = new D
    println(d.message)
    println(d.loudMessage)

8.1、静态动态混入案例1

trait Add{
  def add(a:Int,b:Int):Int
}
trait Minus{
  def minus(a:Int,b:Int):Int
}
class T extends Add with Minus{
  override def add(a: Int, b: Int): Int = a+b
  override def minus(a: Int, b: Int): Int = a-b
}
class X
object TX{
  def main(args: Array[String]): Unit = {
    println((new T).add(1, 2))//静态继承
    println(new X with Add with Minus {//随机动态混入
      override def add(a: Int, b: Int): Int = a * a + b * b
      override def minus(a: Int, b: Int): Int = a - b
    }.add(2, 3))
  }
}

8.2、静态动态混入案例2

  • 强制动态混入
  • this:Type=> 自身类型,表示该类实例化时必须混入相应特质或子特质,self是this的别名。
class Drawing{
//this:Type=> 自身类型,表示该类实例化时必须混入相应特质或子特质,self是this的别名。
  self:Shape => 
  def start()=draw()
}
trait Shape{
  def draw():Unit
}
trait Square extends Shape{
  def draw():Unit ={
    println("draw a square")
  }
}
trait Triangle extends Shape{
  def draw(): Unit = println("draw a triangle")
}
    (new Drawing() with Triangle).start() //动态混入

九、内部类

  • Scala内部类绑定到外部类的对象实例
  • 每个外部类的对象实例new出来的内部类实例都不是同一类型
class Graph{
  class Node{
    var connectNodes:List[Node] = Nil //定义一个空集合
    def connectTo(node:Node): Unit ={
      if (connectNodes.find(node.equals).isEmpty) {
        connectNodes = node::connectNodes //::为向链表的头部追加元素node
      }
    }
  }
  var nodes:List[Node] = Nil
  def newNode:Node={
    val res = new Node
    nodes = res::nodes
    res
  }
}
    val g:Graph = new Graph
    val n1:g.Node = g.newNode
    val n2:g.Node = g.newNode
    n1.connectTo(n2)
    val h:Graph = new Graph
    val n3:h.Node = h.newNode
//    n1.connectTo(n3)
    // 报错:Type mismatch, expected: g.Node, actual: h.Node

十、样例类

  • 主构造器中,使用 val 的定义的变量自动生成 getter,var 定义的变量自动生 成 getter&setter。
  • 相当于伴生对象+伴生类
  • 内置实现了apply,不用new
  • 可以通过样例类,批量创建对象
case class Student2(var name:String,var age:Int){
  def apply(name: String, age: Int): Student2 = new Student2(name, age)
}
object Student2{
  def main(args: Array[String]): Unit = {
    val stu = Student2("henry",18) //实例化不用new关键字
    println(stu.name) //调用自动生成的getter方法
    println(stu.age)
    stu.name_= ("pola") //调用自动生成的setter方法
    println(stu.name)
    println(stu.apply("pola", 18))
  }
}
case  class Student3(name:String,age:Int,gender:String)
object Student3{
  def main(args: Array[String]): Unit = {
    var arr = Array(("a",18,"z"),("a",18,"z"),("a",18,"z"))
    arr.map(x=>Student3(x._1,x._2,x._3)).foreach(x=>println(x))
  }
}

十一、泛型

  • class Foo[+T]协变类:对于两种类型 A 和 B,如果 A 是 B 的子类型,那么 Foo[A] 就是 Foo[B] 的子类型
  • class Bar[-T]逆变类:对于两种类型 A 和 B,如果 A 是 B 的子类型,那么 Bar[B] 就是 Bar[A] 的子类型
  • class Baz[T]不变类不变:默认情况下,Scala中的泛型类是不变的
class Stack[T]{
  var elements:List[T] = Nil
  def push(x:T): Unit ={
    elements = x::elements
  }
  def top:T = elements.head
  def pop(): Unit ={
    var t = elements.head
    elements = elements.tail
    t
  }
  def showElements(): Unit ={
    elements.foreach(x=>print(s"$x "))
    println()
  }
}
object Stack{
  def main(args: Array[String]): Unit = {
    val stack1 = new Stack[Int]
    stack1.push(10)
    stack1.push(20)
    stack1.push(30)
    stack1.showElements()
    stack1.pop()
    stack1.showElements()

    val stack2 = new Stack[String]
    stack2.push("a")
    stack2.push("b")
    stack2.push("c")
    stack2.showElements()
    stack2.pop()
    stack2.showElements()
  }
}
  • 协变,下边界,类型只能更大
object GTDemo{
  //逐级继承的类
  class A1
  class B1 extends A1
  class C1 extends B1

  //泛型B比B1大
  class T[B>:B1]

  def main(args: Array[String]): Unit = {
    new T[B1]
    new T[A1]
    new T[C1] //因为C1更小,报错:type arguments [oop.GTDemo.C1] do not conform to class T's type parameter bounds [B >: oop.GTDemo.B1]new T[C1]
  }
}
  • 逆变,上边界,类型可以更小,但不能更大
object GTDemo{
  //逐级继承的类
  class A1
  class B1 extends A1
  class C1 extends B1

  //泛型B比B1大
  class T1[B>:B1]
  class T2[B<:B1]
  class T3[B]
  
  //上边界
  def main(args: Array[String]): Unit = {
        new T2[B1]
        new T2[A1]//因为A1更大,报错:Error:(261, 11) type arguments [oop.GTDemo.A1] do not conform to class T2's type parameter bounds [B <: oop.GTDemo.B1] new T2[A1]
        new T2[C1]
  }
}
  • 默认时,指定使用其子类
object GTDemo{
  //逐级继承的类
  class A1
  class B1 extends A1
  class C1 extends B1

  //泛型B比B1大
  class T1[B>:B1]
  class T2[B<:B1]
  class T3[B]{
    def show(v: B): Unit ={
      println("abc")
    }
  }
  def main(args: Array[String]): Unit = {
    new T3[B1].show(new B1)
    new T3[B1].show(new A1)//报错:Type mismatch, expected: GTDemo.B1, actual: GTDemo.A1
    new T3[B1].show(new C1)
  }
}
  • 严进宽出,向下兼容
object GTDemo{
  class A1

  trait Add[A,B,C]{
    def +(a:A,b:B):C
  }
  def main(args: Array[String]): Unit = {
    val a = new A1 with Add[Short,Int,Double]{
      override def +(a: Short, b: Int): Double = a+b
    }
    a.+(2,2.toShort)
    a.+(2,2.toByte)
    a.+(2,2.toFloat)//报错,默认严进宽出,向下兼容
  }
}

十二、模式匹配

  • 格式上和Java里的switch case类似
  • 使用上和偏函数是绝配,一般用来做数值区间、正则配合、匹配数据类型、匹配格式等几种用途

案例1:正则匹配

object matchtest{
  def main(args: Array[String]): Unit = {
    var email = "702503235@qq.com"
    val rst = email match {
      case e if (e.matches("^\\w+@[0-9a-z]{2,10}\\.(com|cn|edu|org)$")) => e match {
        case e if (e.matches(".*@qq\\..*")) => Some("qq")
        case e if (e.matches(".*@163\\..*")) => Some("163")
        case e if (e.matches(".*@hotmail\\.*")) => Some("hotmail")
        case e => Some("Others")
      }
      case e => None
    }
    println(rst)
    println(rst.get)
  }
}

在这里插入图片描述
案例2:数据类型匹配

object matchtest2{
  def main(args: Array[String]): Unit = {
    ("a",true,18,20.22,'b',20L,20.1f).productIterator.foreach(x=>println(x match {
      case i:String=>s"${i} is a String"
      case i:Boolean=>s"${i} is a Boolean"
      case i:Int=>s"${i} is a Int"
      case i:Double=>s"${i} is a Double"
      case i:Char=>s"${i} is a Char"
      case i:Long=>s"${i} is a Long"
      case i:Float=>s"${i} is a Float"
      case i=>None
    }))
  }
}

在这里插入图片描述
案例3:格式匹配

object matchtest3{
  def main(args: Array[String]): Unit = {
    val products = Array((1,2,3),((1,2),3),(1,(2,3)),())
    products.foreach(x=>println(x match {
      case (a,b,c)=>"A"
      case ((a,b),c)=>"B"
      case (a,(b,c))=>"C"
      case e=>None
    }))
  }
}

在这里插入图片描述
案例4:样例类的模式匹配

object matchtest4{
  //样例类的模式匹配
  def matchTest4(x: Student2)= x match {
    case Student2(name,19) => println(name)
    case Student2("Tom",age) => println(age)
    case Student2(name,age) => println(name,age)
    case _ => println("no matches")
  }

  def main(args: Array[String]): Unit = {
    matchTest4(Student2("Jason",19))
    matchTest4(Student2("Tom",20))
    matchTest4(Student2("Jimmy",20))
  }
}

在这里插入图片描述
案例5:非样例类的模式匹配

class Student(n:String,a:Int){
  private var name = n
  private var age = a
}
object Student{
  def apply(n: String, a: Int): Student = new Student(n, a)

  def unapply(arg: Student): Option[(String, Int)] = {
    if (arg==null)None else Some(arg.name,arg.age)
  }
  def matchtest(x:Student) = x match {
    case Student(name, age) if age<20 => println("too young")
    case Student(name, age) if age>20 => println("too old")
  }
  def main(args: Array[String]): Unit = {
    val stu=Student("Jason",9) //通过伴生对象的apply()方法创建实例
    println(stu.name)
    matchtest(stu)
    matchtest(Student("zhangsan",33))
  }
}

在这里插入图片描述

十三、运算符重载

object oper{
  case class Vec(val x: Double, val y: Double) {
    def +(that: Vec) = new Vec(this.x + that.x, this.y + that.y)
    def add(that: Vec) = new Vec(this.x + that.x, this.y + that.y)
  }
  def main(args: Array[String]): Unit = {
    val vector1 = Vec(1.0, 1.0)
    val vector2 = Vec(2.0, 2.0)
    val vector3 = vector1 + vector2  // 或者 vector1 add vector2
    println(vector3.x)
    println(vector3.y)
  }
}

在这里插入图片描述

//运算符重载
object oper2{
  case class Group(eles:Int*){
    def ++() = eles.sum
    def +(g:Group) = (g++)+(this++)
  }

  def main(args: Array[String]): Unit = {
    val g1 = Group(1,2,3)
    val g2 = Group(4,5,6)
    println(g1 ++)
    println(g1+g2)
  }
}

在这里插入图片描述

十四、隐式类

  • 隐式类指的是用implicit关键字修饰的类。在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换。
  • 隐式类有以下限制条件:
    只能在别的trait/类/对象内部定义
    构造函数只能携带一个非隐式参数。虽然我们可以创建带有多个非隐式参数的隐式类,但这些类无法用于隐式转换。
    在同一作用域内,不能有任何方法、成员或对象与隐式类同名。
object yinshiclass{
  implicit class A(x:Int){
    def add(y:Int)=x+y
  }
  def main(args: Array[String]): Unit = {
    println(2 add 3)
  }
}

在这里插入图片描述

十五、闭包

  • 可以访问一个函数里面局部变量的另一个函数
  • 进函数后,变量的值就不会改变
object bibao{
  def main(args: Array[String]): Unit = {
    var factor = 2.3
    val cal = (x:Int) =>x*factor//进函数后,factor的值就不会改变
  }
}

十六、正则

  • 使用 String 类的 matches()方法
  • 使用 Regex(scala.util.matching.Regex)的提取器进行模式匹配
  • 使用 Regex API
    1、matches方法
object regex{
  def main(args: Array[String]): Unit = {
    println("1232sdfsdf".matches("^\\d+\\w+$"))
    println("1232-sdfsdf".matches("^\\d+\\w+$"))
    println("1232-sdfsdf".matches("^\\d+[^a-z0-9]\\w+$"))

在这里插入图片描述

2、构造Regex对象,使用提取器

  • 提取器有三种方式,无分组、单分组、多分组
    import scala.util.matching.Regex
    val decimal1=new Regex("(-)?(\\d+)(\\.\\d*)?")
    //包含了很多转义符可以使用三引号
    val decimal2=new Regex("""(-)?(\d+)(\.\d*)?""")
    val decimal3="""(-)?(\d+)(\.\d*)?""".r

    println("---Regex 的提取器-无分组---")
    val p1 = "ab*c".r
    //调用时把p1当做方法调用,加括号p1()
    val p1m = "abbbc" match {
      case p1() => true
      case _=>false
    }
    println(p1m)

    println("---Regex 的提取器-单分组---")
    //前提是case p1() => true
    val p2 = "a(b*)e".r
    //(b*)是p2中的一个分组,所以“case p2(a1)”表示正则匹配到分组内容
    // 并赋值给变量“a1”
    val p2m = "abbbe" match {
      case p2(a1) =>Some(a1)
      case _=>None
    }
    println(p2m)

    println("---Regex 的提取器-多分组---")
    //前提是case p1() => true
    val p3 = "a(b*)(c*)(d*)e".r
    //(b*)是p2中的一个分组,所以“case p2(a1)”表示正则匹配到分组内容
    // 并赋值给变量“a1”
    val p3m = "abbbcccddde" match {
      case p3(a1,a2,a3) =>Some(a1,a2,a3)
      case _=>None
    }
    println(p3m)

在这里插入图片描述

3、使用RegexAPI

  • findFirstMatchIn() 返回第一个匹配(Option[Match])
  • findAllMatchIn() 返回所有匹配结果(Regex.Match)
  • findAllIn() 返回所有匹配结果(String)
  • Match 是对匹配结果的描述,主要方法有:
    • groupCount:获取所有捕获的分组总数
    • group():获取指定的分组,分组由 0 开始编号
    • subgroups:所有捕获的分组,不包括分组 0
    println("---使用RegexAPI - Regex 查找 ---")

    println("---捕获分组和输出捕获的内容---")
    val p4 = "a((b*))c".r
    val m=p4.findFirstMatchIn("abbc").get//两个括号因此捕获了两个分组
    (0 to m.groupCount).map(m.group).foreach(println)
    println()
    m.subgroups.foreach(println)

    println("---多 Match 分组处理---")
    val studentPattern:Regex="([0-9a-zA-Z-#() ]+):([0-9a-zA-Z-#() ]+)".r
    val input="name:Jason,age:19,weight:100"
    for(patternMatch<-studentPattern.findAllMatchIn(input)){
      println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}")
    }
    println("---Regex 字符串替换---")
    println("[0-9]+".r.replaceFirstIn("234 Main Street Suite 2034", "567")) //234->567
    println("[0-9]+".r.replaceAllIn("234 Main Street Suite 2034", "567")) //234、2034->567
    println("[0-9]+".r.replaceAllIn("234 Main Street Suite 2034", m => {
      if (m.group(0).length == 3) "567"
      else m.group(0)
    }))
  }
}

在这里插入图片描述

十七、异常

  • 异常有三种处理方式,分别为try catch、Either[A,B]、allCatch
object exception {
  try {
    //todo
  } catch {
    case ex: 异常类型 => {
      //todo }
      … …
    } finally
    {
      //todo
    }
  }
  //Either[A, B] 表示要么包含一个类型为 A 的实例,要么包括一个类型为 B 的 实例。
  // Either 有两个子类型,Left、Right,
  // 如果 Either[A, B]对象包含的是 A 的实 例,则它是 Left 实例,否则是 Right 实例
  // Either 用于异常处理时,一般约定:Left 代表出错的情况,Right 代表成功 的情况
  def divide(x:Int): Either[String,Int] ={
    if(x==0)
      Left("除数不能为 0")
    else
      Right(100/x)
  }
  def test(x: Int) = divide(x) match {
    case Left(errMsg) => println(errMsg)
    case Right(result) => println(result)
  }

  def main(args: Array[String]): Unit = {
    test(0)
    test(1)
    }
  }

在这里插入图片描述

object exception {
  def main(args: Array[String]): Unit = {
    println("---allCatch---")
    //allCatch 是 scala.util.control.Exception 单例对象的方法。返回 Catch 类

    println("---allCatch opt()方法---")
    //将此 Catch 捕获逻辑应用于所提供的主体,将结果映射到“Option[T]”:
    //如果 捕获了任何异常,则映射到“None”,否则映射到“Some(T)”。
    println(scala.util.control.Exception.allCatch.opt("42".toInt))
    println(scala.util.control.Exception.allCatch.opt("42a".toInt))
    println("---allCatch toTry()方法---")
    //如果发生异常,封装为 Failure 对象,否则执行表达式。
    println(scala.util.control.Exception.allCatch.toTry("42".toInt))
    println(scala.util.control.Exception.allCatch.toTry("42a".toInt))

    println("---allCatch withTry()方法---")
    // withTry()方法 返回 scala.util.Try 对象,其有两个子类型,Success 和 Failure,
    // 分别表示运行 正常与异常,本质是调用 toTry(Success(body))。
    println(scala.util.control.Exception.allCatch.withTry("42".toInt)) // Success(42)
    println(scala.util.control.Exception.allCatch.withTry("42a".toInt)) // Failure (e)
    println("---allCatch either()方法---")
    // either()方法 返回两种类型,正确为 Right,有错误为 Left。
    println(scala.util.control.Exception.allCatch.either("42".toInt)) // Right(42)
    println(scala.util.control.Exception.allCatch.either("42a".toInt))
  }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值