trait-多继承详解

37 阅读2分钟

1多个trait的加载顺序

【码】讲解并示范

trait  AA051 {  println("AA051") }  
trait  AB051 {  println("AA051") }  
trait  BA051 {  println("BA051") }  
trait  BB051 {  println("BB051") }  
  
class AB extends AA051 with BA051 with AB051 with BB051 {  
  println("AB")  
}  
  
object Test21 {  
  def main(args: Array[String]): Unit = {  
    new AB()  
  }  
}

2多层trait的加载顺序

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

trait  A051 { println("A051")}  
  
trait  AA051 extends  A051 {  println("AA051") }  
  
trait  AB051 extends  A051 {  println("AA051") }  
  
trait  B051 { println("B051") }  
  
trait  BA051 extends  B051 {  println("BA051") }  
  
trait  BB051 extends  B051 {  println("BB051") }  
  
class AB extends AA051 with BA051 with AB051 with BB051 {  
  println("AB")  
}  
  
object Test21 {  
  def main(args: Array[String]): Unit = {  
    new AB()  
  }  
}

3空指针异常

trait FileLogger {

   println(s"FileLogger ${filename}")

   val filename:String  
   val fileout = new PrintWriter(filename)

   def log(msg:String) = {

     fileout.println(msg)

     fileout.flush()

   }

 }

class Person051 extends FileLogger {

  override  val filename = "p051.log"

}

object Test19 {

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

    val p = new Person051()

    p.log("person051 create log")

  }

}

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

方法1:懒加载

lazy val fileout = new PrintWriter(filename)

方法2:提前定义

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

4trait与抽象类的区别

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

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