Scala入门(五)面向对象

  • 对象 object
  • 类 class
  • 特质 trait
  • 继承
  • 样例类 case class
  • 模式匹配

类: class关键字修饰,可用new class()来实例化
对象: object关键字修饰

1. 对象

1.1 单例对象

Scala中没有静态方法和静态字段,没有static,用object关键字修饰的对象是单例的,称为单例对象,静态对象。

object Singleton {
    def do(msg: String) = {
        println(msg)
    }
}

1.2 伴生对象

伴生对象是一种特殊的单例对象。是一种相对概念,需要满足两个条件:
条件1:在同一个源文件中,
条件2:对象名和类名相同
这样的单例对象,被称作是这个类的伴生对象。类被称为是这个单例对象的伴生类。
结论:类和伴生对象之间可以相互访问私有的方法和属性

class Dog {
  val id = 1
  private var name = "xiaoqing"
  def printName(): Unit ={println(Dog.CONSTANT + name )}  //在Dog类中可以访问伴生对象Dog的私有属性
}

object Dog {
  private val CONSTANT = "汪汪汪 : "
  def main(args: Array[String]) {
    val p = new Dog
    p.name = "123"
    p.printName()
  }
}

1.3 apply方法

伴生对象中通常会定义apply方法,目的:不需通过new关键字,更方便的完成类和实例对象的初始化。

object ApplyDemo {
    def apply(msg:String) = {
      print(s"主食 油泼面,小菜:$msg")
    }
  def apply(i:Int):Int = { i * i }
  def main(args: Array[String]) {
    val arr1 = Array(5)    //调用了Array伴生对象的apply方法
    println(arr1.toBuffer)
    println(ApplyDemo("海参炒面"))
    println(ApplyDemo.apply("油炸煎饼"))
    println(ApplyDemo(1))
  }
}

2. 类

2.1 类的定义

Scala源文件中可以包含多个类,所有这些类都具有公有可见性。

class Student {
}

2.2 构造器

构造器分为两种:主构造器和辅助构造器
主构造器直接在类名后面定义,每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起。
辅助构造器自定义,使用def this关键字,而且必须调用主构造器,或者其他的辅助构造器

class Person(val name: String, val age: Int){
  println("执行主构造器")  //主构造器会执行类定义中的所有语句
  private var gender = "male"
  
  def this(name: String, age: Int, gender: String){   //用this关键字定义辅助构造器
    this(name, age)  //每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
    println("执行辅助构造器")
    this.gender = gender
  }
  var account1:String=_

  def this(name:String,age:Int,gender:String){
    this(name,age)
    this.gender=gender
  }
  def this(name:String,age:Int,gender:String,account:String){
    this(name,age,gender)
    this.account1=account
  }
 println("尼玛,这里还是主构造器")
}
object Person {
    def   main(args: Array[String]): Unit = {
        val s = new Person ("laoduan", 38)    //主构造器
        println(s"${s.name} ${s.age}")

        val s1 = new Person (“dingding", 18, "female")   //辅助构造器
        println(s"${s1.gender}")
        val p2 =new Person("xx2",12,"female","9527")   //辅助构造器
        println(s"${p2.age},${p2.account1}")
    }
}

2.3 访问权限

public:默认权限,任何地方均可访问
private:类和其伴生对象中可访问,new出来的对象不可访问
private [this]:当前类可访问,伴生对象无效
private [packageName]: 指定包及其子包有效,直接写包名,不需要写路径如 private [scalaTest]即可

2.4 抽象类

abstract class Animal {
    println("Animal's constructor ....")
    val name: String = "animal"   // 定义一个name属性
    def sleep()    // 没有任何实现的方法
    def eat(f: String): Unit = {   // 带有具体的实现的方法
        println(s"$f")
    }}

3 特质 Trait

Trait(特质)相当于 java的接口。
Scala的类只能单一继承,但是可以实现(继承,混入)多个特质(Trait)使用的关键字是 withextends.
特质可以定义方法体
scala可以在一个class实例化的时候动态混入trait

trait T1 {
  // 定义普通方法,有方法实现
  def youcanfly()={
    println("tai feng lai le you can fly")
  }
}

trait T2 {
    val className: String = "scala学习"    // 定义一个属性
    def doNothing(name: String)     // 定义一个没有实现的方法,默认就是抽象方法
    def doSomething() = {      // 定义带有具体的实现的方法
        println("简单scala")
    }
}

object test{
  def main(args: Array[String]): Unit = {
    val t1 = new Teacher with T1    // 动态混入特征,让类有了特质的方法
    println(t1.youcanfly())
    
    val t = new Teacher() with T1 with T2{   // 动态混入特质不能使用extends关键字,可同时混入多个特质
      def doNothing(name:String)={      // // 如果特质中有抽象方法,则必须重写该抽象方法,可以不使用override关键字
        println(s"定义特质方法,${name}")
      }
    
   override def doSomething() = {            // 重写一个有具体的实现的方法,必须使用关键字override
        println("重写具体实现方法,必须写override")
    }
    }
    println(t.teach("laozhao"))
    println(t.doSomething)
    println(t.youcanfly())
  }
}

4. 继承

当类只实现了特质的时候,第一个关键字必须是extends
实现类还是特质,抽象方法都必须被实现,而且可以不使用override关键字
重写非抽象方法,必须使用override关键字
特质支持动态混入,在类实例化的时候,可以通过with关键字混入特质。
特质不能有构造器,抽象类可以有。

5. 样例类 case class/样例对象 case object

样例class:使用case关键字 修饰的类,重要的特征就是支持模式匹配,多例
样例object:使用case关键字修饰的对象,支持模式匹配,单例
有参数用case class,无参用case object
case class 和 class的一些区别:
 1) case class在初始化的时候,不用new,而普通类初始化时必须要new。
 2) case class 重写了toString方法。
 3) 默认实现了equals和hashCode
 4) case class 实现了序列化接口
 5) case class 支持模式匹配(最重要的特征),所有case class 必须要有参数列表

case class Message(msg: String)  //样例类,使用case 关键字 修饰的类, 其重要的特征就是支持模式匹配

case object CheckHeartBeat  //样例object, 不能封装数据, 其重要特征就是支持模式匹配

object TestCaseClass extends App{
    val msg = Message("hello")  // 可以不使用new 关键字创建实例 
    println(msg.msg)
}

6 模式匹配

快速匹配,基本关键字为match和case

object CaseDemo01 extends App{
  val arr = Array("123", "456", "777")
  val name = arr(Random.nextInt(arr.length))
  name match {
    case "123" => println("你好这里是123")
    case "456" => println("你好这里是456")
    case _ => println("谢谢使用")
  }

object CaseDemo02 extends App{
  //val v = if(x >= 5) 1 else if(x < 2) 2.0 else "hello"
  val arr = Array("hello", 1, 2.0, CaseDemo2)
  val v = arr(Random.nextInt(arr.length))
  println(v)
  v match {
    case x: Int => println("Int " + x)
    case y: Double if(y >= 0) => println("Double "+ y) // if 守卫
    case z: String => println("String " + z)
    case CaseDemo02 => {
      println("case demo 2")
    }
    case _ => throw new Exception("not match exception")
  }
}

object CaseDemo03 extends App{
  val arr = Array(1, 3, 5)
  arr match {
    case Array(1, x, y) => println(x + " " + y)
    case Array(0) => println("only 0")
    case Array(0, _*) => println("0 ...")
    case _ => println("something else")
  }
  val lst = List(3, -1)
  lst match {
    case 0 :: Nil => println("only 0")
    case x :: y :: Nil => println(s"x: $x y: $y")
    case 0 :: tail => println("0 ...")
    case _ => println("something else")
  }
  val tup = (2, 3, 5)
  tup match {
    case (2, x, y) => println(s"1, $x , $y")
    case (_, z, 5) => println(z)
    case  _ => println("else")
  }
}

case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask

object CaseDemo04 extends App{
  val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
  arr(Random.nextInt(arr.length)) match {
    case SubmitTask(id, name) => {
      println(s"$id, $name")
    }
    case HeartBeat(time) => {
      println(time)
    }
    case CheckTimeOutTask => {
      println("check")
    }
  }
}

object PartialFuncDemo  {
  def func1(num: String) : Int = num match {
    case "one" => 1
    case "two" => 2
    case _ => -1
  }
  def func2: PartialFunction[String, Int] = {   //偏函数,它是PartialFunction[A, B]的一个实例,A代表输入参数类型,B代表返回类型,常用作输入模式匹配
    case "one" => 1
    case "two" => 2
    case _ => -1
  }
  def main(args: Array[String]) {
    println(func1("one"))
    println(func2("one"))
  }
}

object PartialFunctionDemo2 {
  def f:PartialFunction[Any,Int]={
    case i:Int => i *10
    case _ => i *10
  }
  def main(args: Array[String]): Unit = {
    val arr = Array(1,3,5,"seven")
    val collect: Array[Int] = arr.collect {
      case t: Int => t * 10
    }
    println(collect)
    arr.collect(f).foreach(println)    //偏函数最常用的就是方法中要求传入偏函数的类型。
  }
}

总结

类和对象:object无构造器,必须是无参的,对象本质拥有类的所有特性,如果不需要构造器封装数据,优先使用object
特质和抽象类:
1)优先使用特质,一个类可以扩展多个特质,但却只能扩展一个抽象类。
2)如果需要构造方法,使用抽象类。因为抽象类可以定义带参数的构造器,而特质不行

你可能感兴趣的:(Scala入门(五)面向对象)