trait基本使用(二)

55 阅读2分钟

内容如下:

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

2.解决报错的代码:空指针异常

3.trait 和 class 的区别

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

如果是多继承,有多个trait,按书写顺序从左到右

package level02

/*
 特质
 trait:实现多继承
 trait多继承构造器的执行顺序
 1. 先父 后子
 2. 如果是多继承,有多个trait,按书写顺序从左到右
*/
object class15 {

  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()
  }
}

运行代码如下:

image.png

【实现下图图例 代码示范】 屏幕截图 2025-11-18 083240.png

package level02

/*
 特质
 trait:实现多继承
 trait多继承构造器的执行顺序
 1. 先父 后子
 2. 如果是多继承,有多个trait,按书写顺序从左到右
*/
object class15 {

  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()
  }
}

运行代码如下: image.png

(二)解决报错的代码:空指针异常

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

【代码如下】:

package level02
import java.io.FileWriter

/*
*/
object class16 {

  trait FileLogger{

    println("FileLogger")

    val filename:String

    // 懒加载机制 lazy
    // 这个对象不会立刻创建,而是等到你需要使用的时候才会创建
    
    lazy val writer = new FileWriter(filename)

    def writeLog(msg:String):Unit = {
      writer.write(msg)
      writer.close()
    }
  }

  class MyWriter extends FileLogger {

    println("MyWriter")

    override val filename: String = "test.log"
  } // 继承 三个特质A,B,C

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

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

问题解决:

方法1:懒加载

lazy val fileout = new PrintWriter(filename)

方法2:提前定义

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

(三)trait 和 class 的区别

相同点:类和trait都可以定义成员变量(抽象,具体);继承时都使用extends关键字

不同点:trait的构造器不能带参数;trait支持多继承

package level02

import java.io.FileWriter

/*
  trait 和 class 的区别:

  1. class 类。 伴生类,抽象类,内部类,不能多继承。
  2. trait 特质。 可以多继承,构造器不能带参数。 extends  with

  共同点:
1. 都可以有:具体属性,抽象属性。具体方法、抽象方法
2. 都使用extends来继承

*/
object class17 {
  class A{}
  trait B{}

  class AB extends A with B{

  }

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

  }
}