Scala—trait高级用法

21 阅读2分钟

一、实现多个特质

格式:类名 extends 特质1 with 特质2 with 特质3  其中多个特质的顺序可以交换。

二、多个trait的加载顺序

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

构造器的执行顺序:

  • 1.先父 后子;
  • 2.如果是多继承,有多个trait,按书写顺序从左到右。
trait AA {
  println("AA 特质构造器")
}

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

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

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

trait C extends CC{
  println("C    构造器")
}

// 继承 with
class Child() extends C with B with A{
    println("child ...")
  }   // 继承三个特质A,B,C

三、空指针异常

以下代码有问题,大家先看看哪里有问题?

trait FileLogger {
  val filename:String

  val writer = new FileWriter(filename)

  def writeLog(msg:String):Unit = {
    writer.write(msg)
    writer.close()
  }
}

// 继承 with
class MyWriter extends FileLogger {

  println("MyWriter")
    override val filename: String = "test.log"
  } 

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

问题解决:

  • 方法1:懒加载

lazy val writer = new PrintWriter(filename)

  • 方法2:提前定义

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

四、trait与类的区别

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

1.class 类。伴生类,抽象类,内部类。不能多继承。

2.trait 特质。可以多继承。构造器不能带参数。 extends with

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

1.都可以有:具体属性,抽象属性,具体方法,抽象方法。

2.都使用extends来做继承。

class A{}
trait B{}

class AB extends A with B{

}