Scala中trait多继承详解

54 阅读2分钟

多个trait的加载顺序

有多个父类,则按照从左到右的顺序调用。

image.png

/*
* 多继承时,构造器调用顺序
* 1. 先父后子。先调用父类构造器,再调用子类构造器
* 2. 有多个父类,从左到右的顺手去调用构造器
* */
object class21 {

  trait A {
    println("trait A")
  }

  trait B {
    println("trait B")
  }

  trait C {
    println("trait C")
  }

  class Class1 extends A with B with C{
    println("class 1...")
  }

  def main(args: Array[String]): Unit = {
    new Class1()
  }
}

多层trait的加载顺序

先执行父类中的构造器,再执行子类的构造器:如果trait1也有自己的父类,要先执行父类构造器 image.png

/*
* 多继承时,构造器调用顺序
* 1. 先父后子。先调用父类构造器,再调用子类构造器
* 2. 有多个父类,从左到右的顺手去调用构造器
* */
object class21 {

  trait A {
    println("trait A")
  }

  trait BB {
    println("trait BB")
  }

  trait B extends BB {
    println("trait B")
  }

  trait CC {
    println("trait CC")
  }

  trait C extends CC {
    println("trait C")
  }

  class Class1 extends A with B with C{
    println("class 1...")
  }

  def main(args: Array[String]): Unit = {
    new Class1()
  }
}

输出结果:

trait A
trait BB
trait B
trait CC
trait C
class 1...

trait和class区别

  1. 相同点。
  • 可以被继承,extends
  • 属性和方法:抽象属性,具体属性,抽象方法,具体方法
  • 都不能被实例化。不能new
  1. 不同点
  • trait 支持多继承; 抽象类不能多继承
object class23 {

  trait A {
    println("trait A")
  }

  trait B {
    println("trait B")
  }
  class C extends A with B {
    
  }

  def main(args: Array[String]): Unit = {
    new C()
  }
}

空指针异常

懒加载

import java.io.FileWriter
/*
*  空指针异常
*
* 目标:实现日志类,可以把一些文本信息写入指定的文件中
*
* */
object class24 {
  trait Log {
    // 抽象属性:文件名,
    var fileName:String

    println(s"${fileName}")
    // 具体属性
    // lazy 懒加载,懒
    lazy val fileWriter:FileWriter = new FileWriter(fileName)

    def writerLog(msg:String): Unit = {
      fileWriter.write(msg)
      fileWriter.close()
    }
  }
  // 先执行父类构造器,所以报错
  class TextLog extends Log {

    var fileName:String = "text01.log"
  }

  def main(args: Array[String]): Unit = {
    val textLog = new TextLog()
    textLog.writerLog("2025-11-19: 下午,天气晴朗")
  }
}