Scala面向对象

1. 面向对象概述

  1. Java / Scala OO(Objecet Orientaed)
    • 封装:属性、方法封装到类中
    • 继承:父类和子类之间的关系
    • 多态:父类引用指向子类对象(重要)

2. 类的定义与使用

/**
 * Author: 3zZ.
 * Date: 2020/1/3 4:55 下午
 */
object SimpleObjectApp {
  def main(args: Array[String]): Unit = {
    val person = new People()
    person.name = "messi"
//    person.age = 30
    println(person.name + ".." + person.age)
    println("invoke eat method:"+person.eat())
    person.watchTv("basailuona")
    person.sex()
  }
}
class People{
  // 定义属性
  // var可以自动生成 getter 和 setter
  // _ 是占位符
  var name:String = _
  // val只能自动生成 getter
  val age:Int = 10
  private [this] val gender = "male"
  // 定义方法
  def eat():String = {
    name+ "eat..."
  }
  def sex(): Unit ={
    println("gender is " + gender)
  }
  def watchTv(teamName:String): Unit ={
    println(name + "is watching " + teamName)
  }
}
// 返回
messi..10
invoke eat method:messieat...
messiis watching basailuona
gender is male
  • 占位符_
    • 定义占位符必须使用var
    • 定义之前必须先确定变量的类型
  • private [this]关键字的变量
    • 只能在类的内部被拿到

3. 构造器

/**
 * Author: 3zZ.
 * Date: 2020/1/3 6:23 下午
 */
object ConstructorApp {
  def main(args: Array[String]): Unit = {
    val person = new Person("zhangsan", 30)
    println(person.school + ": "+person.name+" : "+ person.age)
    val person2 = new Person("3zz", 18,"M")
    println(person2.school + ": "+person2.name+" : "+ person2.age+":"+person2.gender)
  }
}
// 主构造器
class Person(val name:String, val age:Int){
  println("Constructor enter..")
  val school = "ustc"
  var gender:String = _
  // 附属构造器
  def this(name:String, age:Int, gender:String){
    this(name, age)// 附属构造器的第一行代码必须要调用主构造器或者其他附属构造器
    this.gender = gender
  }
  println("Constructor leave..")
}
// 返回结果
Constructor enter..
Constructor leave..
ustc: zhangsan : 30
Constructor enter..
Constructor leave..
ustc: 3zz : 18:M
  • 主构造器
    • class关键字后面括号内的内容
  • 附属构造器
    • 类内部的this()方法,需要在第一行调用主构造器或者其他附属构造器
  • 需要注意的是,如果主构造器中的属性没有val或者var,类外部无法调用该属性

4. 继承与重写

  1. 继承
/**
 * Author: 3zZ.
 * Date: 2020/1/3 6:23 下午
 */
object ConstructorApp {
  def main(args: Array[String]): Unit = {
    val student = new Student("3z",18,"CS")
    println(student.name+" : " + student.major)
  }
}
// 主构造器
class Person(val name:String, val age:Int){
  println("Constructor person enter..")
  val school = "ustc"
  var gender:String = _
  // 附属构造器
  def this(name:String, age:Int, gender:String){
    this(name, age)// 附属构造器的第一行代码必须要调用主构造器或者其他附属构造器
    this.gender = gender
  }
  println("Constructor person leave..")
}
class Student(name:String, age:Int,val major:String) extends Person(name, age){
  println("Constructor student enter..")
  println("Constructor student leave..")
}
  • 继承的时候还是属性需要注意
    • 父类已经有的前面可以没有关键字
    • 父类没有的需要添加val或者var
  1. 重写:使用override关键字
/**
 * Author: 3zZ.
 * Date: 2020/1/3 6:23 下午
 */
object ConstructorApp {
  def main(args: Array[String]): Unit = {
    val student = new Student("3z",18,"CS")
    println(student.name+" : " + student.major)
    println(student.toString)
  }
}
// 主构造器
class Person(val name:String, val age:Int){
  println("Constructor person enter..")
  val school = "ustc"
  println("Constructor person leave..")
}
class Student(name:String, age:Int,val major:String) extends Person(name, age){
  println("Constructor student enter..")
  // 重写父类中的school属性
  override val school = "tsing"
  // 重写Object类中的toString()方法
  override def toString: String = {
    "name: " + name +"age :"+age+"school: " + school
  }
  println("Constructor student leave..")
}
// 返回结果
Constructor person enter..
Constructor person leave..
Constructor student enter..
Constructor student leave..
3z : CS
name: 3zage :18school: tsing

5. 抽象类

  1. 类的一个或者多个方法没有完整的实现(只有定义,没有实现)
/**
 * Author: 3zZ.
 * Date: 2020/1/3 10:01 下午
 */
object AbstractApp {
  def main(args: Array[String]): Unit = {
    val student = new Student2()
    println(student.name)
    student.speak
  }
}
abstract class Person2{
  def speak
  val name:String
  val age:Int
}
// 需要重写抽象类中的方法和属性
class Student2 extends Person2 {
  override def speak: Unit = {
    println("speak")
  }
  override val name: String = "3z"
  override val age: Int = 18
}

6. 伴生类与Apply

  1. 伴生类与伴生对象
/**
 * 如果有一个class, 还有一个与class同名的object
 * 那么就称这个object是class的伴生对象,class是object的伴生类
 */
// 伴生类
class ApplyTest{

}
// 伴生对象
object ApplyTest{

}
  1. apply方法

    /**
     * Author: 3zZ.
     * Date: 2020/1/3 10:33 下午
     */
    object ApplyApp {
      def main(args: Array[String]): Unit = {
        for (i <- 1 to 10) {
          ApplyTest.incr
        }
        println(ApplyTest.count) // 说明object本身是一个单例对象
        val b = ApplyTest() // ==> 默认调用 Object.apply 方法
        println("---------------------------")
        val c = new ApplyTest()// 类名() ====> Class.apply()
        println(c) // com.zth.fun.ApplyTest@68c4039c
        c()// 对象() ====> Object.apply()
        // class applytest apply...
      }
    }
    
    /**
     * 如果有一个class, 还有一个与class同名的object
     * 那么就称这个object是class的伴生对象,class是object的伴生类
     */
    // 伴生类
    class ApplyTest {
      def apply() = {
        println("class applytest apply...")
      }
    }
    // 伴生对象
    object ApplyTest {
      println("object applytest enter..")
      var count = 0
      def incr = {
        count += 1
      }
      // 最佳实践:在Object的apply方法中去new Class
      def apply() = {
        println("object applytest apply")
        // 在object中的apply中new class
        new ApplyTest
      }
      println("object applytest leave..")
    }
    // 返回结果
    object applytest enter..
    object applytest leave..
    object applytest apply
    ---------------------------
    com.zth.fun.ApplyTest@68c4039c
    class applytest apply...
    
    • 伴生对象object本身是一个单例对象,只会被调用一次
    • 类名() ====> Class.apply()
    • 对象() ====> Object.apply()
    • apply方法的最佳实践是在伴生对象的apply方法中new 一个伴生类

7. Case Class

  1. 通常用在模式匹配里面
/**
 * Author: 3zZ.
 * Date: 2020/1/3 11:23 下午
 */
// 通常用在模式匹配里面
object CaseClassApp {
  def main(args: Array[String]): Unit = {
    println(Dog("wangcai").name)
  }
}
// case class不用new
case class Dog(name:String)

8. Trait

  1. 相当于Java中的interface

  2. Scala中如何实现多个接口的实现?

    trait xxx extends aTrait with BTrait
    // 实际例子
    class SparkConf(loadDefaults: Boolean)
    	extends Cloneable with Logging with Serializable