Scala中的trait高级用法

34 阅读2分钟

多个trait的加载顺序

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

Snipaste_2025-11-18_08-27-12.png

代码示例:

/*
trait:实现多继承
trait多继承构造器的执行顺序
1、先父,后子
2.如果是多继承,有多个trait,按书写顺序从左到右
 */
object day32 {
   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()
  }
}

运行结果:

C特质构造器
B特质构造器
A特质构造器
child...

多层trait的加载顺序

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

Snipaste_2025-11-18_08-34-04.png

代码示例:

object day33 {
  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()
  }
}

运行结果:

CC 特质构造器
C  构造器
B特质构造器
AA特质构造器
A 构造器
child...

空指针异常

Snipaste_2025-11-18_09-18-07.png 以上报错原因就是空指针异常

解决方法:

方法1.懒加载

import java.io.FileWriter

object day34 {
  trait FileLogger {
    println("fileLogger")
    val filename:String
    //懒加载效果
    //这个对象不会立刻去创建,而是等你需要使用的时候才去创建
    lazy val writer=new FileWriter(filename)
    def writerLog(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.writerLog("测试内容")
  }
}

方法2.提前定义

import java.io.FileWriter

object day34 {
  trait FileLogger {
    val filename: String  
    val writer = new FileWriter(filename)  
    // 写入日志方法
    def writeLog(msg: String): Unit = {
      writer.write(msg)  
      writer.close()   
    }
  }

  // 子类:用【提前定义】解决初始化顺序问题
  class MyWriter extends {
    // 提前定义:在父特质初始化前,先给filename赋值
    // 作用:让FileLogger创建writer时,filename已经有值(不是null),避免NPE
    override val filename: String = "test.log"
  } with FileLogger  // 继承FileLogger特质

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

报错解决完,运行后会生成一个"test.log"的文件

Snipaste_2025-11-18_09-25-47.png

trait与类class的区别

相同点:

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

不同点:

  1. trait的构造器不能带参数;
  2. trait支持多继承;
/*
trait和class的区别
1.class类 伴生类,抽象类,内部类,不能多继承
2.trait特质 可以多继承·,构造器不能带参数  extends   with

共同点
1.都可以有:具体属性,抽象属性,具体方法,抽象方法
2.都使用extends来做继承
 */
object day35 {
   class A{}
   trait B{}
  class AB extends A with B{

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

  }
}