trait多继承

72 阅读2分钟

trait多继承构造器的执行顺序

  1. 先父 后子
  2. 如果是多继承,有多个trait,按书写顺序从左到右

特质 trait: 实现多继承

object class16 {

  trait A {
    println("A 特质构造器")
  }

  trait B {
    println("B 特质构造器")
  }

  trait C {
    println("C 特质构造器")
  }

  class Child extends C with B with A{
    println("child...")
  } // 继承 三个特质A,B,C

  def main(args:Array[String]): Unit = {
    val child = new Child()
  }
}

多层 trait的加载顺序

  1. 先执行父类中的构造器,再执行子类的构造器
  2. 如果c也有自己的父类,要先执行父类构造器
trait AA {
  println("AA 特质构造器")
}

trait A extends AA{
  println("A 构造器")
}

trait B {
  println("B 特质构造器")
}

trait CC {
  println("CC 特质构造器")
}

trait C extends CC{
  println("C 构造器")
}

class Child extends C with B with A{
  println("child...")
} // 继承 三个特质A,B,C

def main(args:Array[String]): Unit = {
  val child = new Child()
}

结果如图所示

屏幕截图 2025-11-18 083639.png

空指针异常

错误代码

trait FileLogger {
  val filename:String
  val writer = new FileWriter(filename)
  def writeLog(msg:String) = {
    writer.write(msg)
    writer.close()
  }
}

class MyWriter extends FileLogger {
  override val filename: String = "test.log"
}

def main(args:Array[String]): Unit = {
  val log = new MyWriter()
  log.writeLog("测试内容")
}

问题分析

调用log.writeLog()时,fileName没有值。这就是继承时带的问题:先执行了trait构造器的代码,后执行了具体子类的构造器。而具体的赋值操作是在子类的构造器中才进行,所以,父类的filename没有值,导致空指针异常

改正

trait FileLogger {

  println("fileLogger")

  val filename:String

  // 懒加载效果
  // 这个对象不会立刻去创建,而是等到你需要使用的时候才去创建
  lazy val writer = new FileWriter(filename)
  def writeLog(msg:String) = {
    writer.write(msg)
    writer.close()
  }
}

class MyWriter extends FileLogger {

  println("MyWriter")

  override val filename: String = "test.log"
}

def main(args:Array[String]): Unit = {
  val log = new MyWriter()
  log.writeLog("测试内容")
}

trait与类的区别

trait 和 class 的区别

1.class类 伴生类,抽象类,内部类,不能多继承

2.trait特质 可以多继承。构造器不能带参数。 extends with

共同点

1.都可以有:具体属性,抽象属性,具体方法,抽象方法

2.都使用extends来做继承