trait-多继承详解

39 阅读2分钟

(一)多个trait的加载顺序

一个类实现了多个特质之后,所涉及的多个构造器的执行顺序如何确定?

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

例如:

屏幕截图 2025-11-19 144426.png

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

object basic21 {

  trait A {
    println("trait A")
  }

  trait B {
    println("trait B")
  }

  trait C {
    println("trait C")
  }


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

 }

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

结果如下:

trait B
trait A
trait C
class 1...

(二)多层trait的加载顺序

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

屏幕截图 2025-11-19 150041.png

package level02

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

object basic21 {

  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 B with A with C {
    println("class 1...")

 }

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

结果如下:

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

(三)空指针异常

import java.io.FileWriter

/**
 * 空指针异常
 *
 * 目标:实现日志类,可以把一些文本信息写入指定文件中
 *
 */

object basic23 {

  trait Log {
    // 文件名,抽象属性
    var fileName:String

    // 具体属性
    // lazy 懒加载,懒
    val fileWriter:FileWriter = new FileWriter(fileName)

    def writeLog(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.writeLog("2015-11-19:下午,天气晴朗")

    }

}

屏幕截图 2025-11-19 153821.png

问题解决

方法:懒加载

lazy val fileout = new PrintWriter(filename)

修改后如下:

import java.io.FileWriter
object basic23 {

  trait Log {
    // 文件名,抽象属性
    var fileName:String

    // 具体属性
    // lazy 懒加载,懒
    lazy val fileWriter:FileWriter = new FileWriter(fileName)

    def writeLog(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.writeLog("2015-11-19:下午,天气晴朗")
    }
}

屏幕截图 2025-11-19 160148.png

(四)trait与类的区别

相同点:

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

不同点:

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

/**
 * trait 和 抽象类class 的区别?
 *
 * 1. 相同点
 *    可以被继承,extends
 *    属性和方法:抽象属性,具体属性,抽象方法,具体方法
 *    都不能被实例化,不能new
 *
 * 2. 不同点
 *    trait 支持多继承:抽象类不能多继承
 */

object basic22 {

  trait A {
    println("trait A")
  }

  trait B {
    println("trait B")
  }

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

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