多继承详解

30 阅读1分钟

特质:trait

一.父子类的构造器执行顺序(多继承)

  1. 先父后子
  2. 有多个父类,按书写顺序从左向右执行
trait A {
  println("A")
}
trait B {
  println("8")
}
class Class1 extends A with B {
  println("Class1")
}
def main(args: Array[String]): Unit = {
  new Class1()
}

输出:

image.png

  1. 当给其中一段代码B增加一个父类
  trait A {
    println("A")
  }
  trait BB {
    println("BB")
  }
  trait B extends BB{
    println("8")
  }
  class Class1 extends B with A {
    println("Class1")
  }
  def main(args: Array[String]): Unit = {
    new Class1()
  }
}

输出:

image.png

二.空指针异常

  1. 懒加载

lazy val fileout = new PrintWriter(filename)

  1. 提前定义

val p = new {override val filename="p052.log"} with Person051

lazy延迟初始化fileWriter,确保filename在使用前已被初始化。

trait FileLogger {
    println(2)
    // 抽象字段,由子类实现
    val filename: String
    // 延迟初始化fileWriter,确保filename赋值后再创建
    lazy val fileWriter = new FileWriter(filename, true)
    def writeLog(msg: String): Unit = {
      fileWriter.write(msg) // 加换行符方便查看
      fileWriter.close()
    }
  }
  class MyFileLogger extends FileLogger {
    println(1)
    // 子类实现filename
    val filename = "11-26.log"
  }

  def main(args: Array[String]): Unit = {
    val fileLogger = new MyFileLogger()
    fileLogger.writeLog("今天上午上scala课程")
  }
}

三.trait与抽象类的区别

  1. 相同点:类和trait都可以定义成员变量(抽象,具体);继承时都使用extends关键字;
  2. 不同点:trait的构造器不能带参数;trait支持多继承;