scala 特质(trait):多继承

66 阅读2分钟

一、特质基础:是什么与核心作用

1. 特质的本质

特质(关键字 trait)是 Scala 中用于封装方法、字段和抽象成员的结构,核心作用有两个:

  • 定义接口规范:包含抽象方法 / 字段,要求实现类必须实现;
  • 提供代码复用:包含具体方法 / 字段,实现类可直接继承使用;
  • 支持多继承:一个类可以同时继承多个特质(用 with 连接),解决了单继承语言的灵活性限制。

二、核心细节:特质构造器执行顺序

特质的构造器执行顺序是新手最容易混淆的点,错误理解可能导致字段初始化异常。我们通过第一个案例拆解规则。

1. 案例:特质与类的继承关系

以下代码定义了多个特质和类,观察实例化子类时的构造顺序:

代码如下

package level02

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

object class16 {

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

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

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

  trait CC {
    println("CC 特质构造器")
  }
  
  class 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()

  }
}

2. 解决方案:早期初始化块

Scala 提供了 “早期初始化块”(Early Initializer),允许在子类继承特质之前,先初始化特质依赖的抽象字段,从而解决初始化顺序问题。

正确代码示例

package level02

import java.io.FileWriter

object class13 {
  trait FileLogger {
    val filename: String
    val writer = new FileWriter(filename) // 此时filename已被早期初始化赋值
    def writeLog(msg: String): Unit = {
      writer.write(msg)
    }
    // 注意:writer.close() 不能放在这里!会导致写入前流已关闭
  }

  // 早期初始化块:{} 中的代码在特质初始化前执行
  class MyWriter extends {
    override val filename: String = "test.log"
  } with FileLogger {
    // 可选:在子类析构时关闭流(或使用try-with-resources)
    def close(): Unit = writer.close()
  }

  def main(args: Array[String]): Unit = {
    val log = new MyWriter()
    log.writeLog("测试内容")
    log.close() // 手动关闭流,确保内容写入文件
  }
}

3. Trait 多继承与 Class 继承演示

package level02

import java.io.FileWriter

// trait 与 class 的区别
// 1. class 特点:单继承,抽象类,内部类,不支持多继承。
// 2. trait 特点:可以扩展多个特质(不能扩展普通类)。 extends  with
// 共同点
// 1. 都可以有:抽象属性,抽象方法,具体方法,抽象方法
// 2. 都使用extends来继承

object class18 {

  trait A{}
  trait B{}

  class AB extends A with B{

  }

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