trait多继承构造器的执行顺序
- 先父 后子
- 如果是多继承,有多个trait,按书写顺序从左到右
特质 trait: 实现多继承
object class16 {
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的加载顺序
- 先执行父类中的构造器,再执行子类的构造器
- 如果c也有自己的父类,要先执行父类构造器
trait AA {
println("AA 特质构造器")
}
trait A extends AA{
println("A 构造器")
}
trait B {
println("B 特质构造器")
}
trait CC {
println("CC 特质构造器")
}
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()
}
结果如图所示
空指针异常
错误代码:
trait FileLogger {
val filename:String
val writer = new FileWriter(filename)
def writeLog(msg:String) = {
writer.write(msg)
writer.close()
}
}
class MyWriter extends FileLogger {
override val filename: String = "test.log"
}
def main(args:Array[String]): Unit = {
val log = new MyWriter()
log.writeLog("测试内容")
}
问题分析:
调用log.writeLog()时,fileName没有值。这就是继承时带的问题:先执行了trait构造器的代码,后执行了具体子类的构造器。而具体的赋值操作是在子类的构造器中才进行,所以,父类的filename没有值,导致空指针异常
改正:
trait FileLogger {
println("fileLogger")
val filename:String
// 懒加载效果
// 这个对象不会立刻去创建,而是等到你需要使用的时候才去创建
lazy val writer = new FileWriter(filename)
def writeLog(msg:String) = {
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("测试内容")
}
trait与类的区别
trait 和 class 的区别
1.class类 伴生类,抽象类,内部类,不能多继承
2.trait特质 可以多继承。构造器不能带参数。 extends with
共同点
1.都可以有:具体属性,抽象属性,具体方法,抽象方法
2.都使用extends来做继承