trait的高级用法(进阶)!!!

33 阅读3分钟

(一)多个trait的加载顺序

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


package level02
object class08 {


  /* 特质
  * trait: 实现多继承(混入多个特质)
  * 构造器的执行顺序
  *1, 先父  后子
  * 如果是多继承,有多个trait ,按照写顺序从左到右
  */
 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的加载顺序

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

image.png


package level02
object class08 {


  /* 特质
  * trait: 实现多继承(混入多个特质)
  * 构造器的执行顺序
  *1, 先父  后子
  * 如果是多继承,有多个trait ,按照写顺序从左到右
  */
 trait AA {
      println("AA 特质构造器 ")
    }
  trait  A extends AA {}
  println("A  构造器")
  trait B {
    println("B 特质构造器 ")
  }
  trait CC{
    println("C 特质构造器 ")

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


}

(三) 空指针异常

object class18 {
  trait FileLogger {
    println("fileLogger")
    val filename: String
    // 延迟初始化writer,确保filename已被子类初始化
    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"
  }

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

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

代码定义了一个特质FileLogger,其中包含一个抽象字段filename、一个延迟初始化的FileWriter对象writer以及一个用于写入日志的方法writeLog;还定义了一个类MyWriter继承自FileLogger并实现了filename字段,最后有一个main方法用于测试。


package level02
object class08 {
  /*
  *
  */

  trait FileLogger{
    println("fileLogger")
    val filename:String
    // 懒加载效果
    // 这个对象不会立刻去创建,而是等到你需要使用的时候才去创建
    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 = "test1.log"
  }// 继承 三个特质A,B,C

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

总结

  1. trair 和 class 的区别
    1. class 类 伴生类 ,抽象类 ,内部类 。不能多继承
    1. trait 特质。 可以多继承 构造器不能带参数 extends with
  1. 共同点
  • 都可以有 :具体属性,具体方法,抽象方法
  • 都使用extends来做继承

  • 完结撒花 !!!!!!!!!!
  • 制作不易 希望·一键三连 在此感谢关注的粉丝宝宝
  • 新来的宝宝可以关注下主播哟!!!!!