内容:
1.多个trait的加载顺序
2.多层trait的加载顺序
3.空指针异常
4.trait与类的区别
多个trait的加载顺序
一个类实现了多个特质之后,所涉及的多个构造器的执行顺序如何确定?
如果有多个父类,则按照从左到右的顺序调用。
代码如下:
package level02
/*
* 特质
* trait:实现多继承
* 构造器的执行顺序
* 1,先父 后子
* 2,如果是多继承,有多个trait,按书写顺序从左到右
*/
object class016 {
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也有自己的父类,要先执行父类构造器
代码如下:
package level02
/*
* 特质
* trait:实现多继承
* 构造器的执行顺序
* 1,先父 后子
* 2,如果是多继承,有多个trait,按书写顺序从左到右
*/
object class016 {
trait AA {
println("A 特质构造器")
}
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()
}
}
输出结果:
CC 特质构造器
C 构造器
B 特质构造器
A 特质构造器
A 构造器
child...
空指针异常
代码如下: 这段代码有错误。
package level02
import java.io.FileWriter
object class017 {
trait FileLogger {
val filename: String
val writer = new FileWriter(filename)
def writeLog(msg:String):Unit = {
writer.write(msg)
writer.close()
}
}
class MyWriter extends {
override val filename:String = "test.log"
}
def main(args: Array[String]): Unit = {
val log = new MyWriter()
log.writeLog("测试内容")
}
}
\scala004\out\production\scala004;C:\Users\admin\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-
2.13.18.jar;C:\Users\admin\.ivy2\cache\org.scala-lang\scala-reflect\jars\scala-reflect-2.13.18.jar level02.class017 Exception in thread "main"
java.lang.NullPointerException at
java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:226) at
java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:123) at
java.base/java.io.FileWriter.<init>(FileWriter.java:66) at
level02.class017$FileLogger.$init$(class017.scala:8)
at level02.class017$MyWriter.<init>(class017.scala:14) at level02.class017$.main(class017.scala:19) at
level02.class017.main(class017.scala)
报错如何解决,哪里有错误?
问题分析
初始化顺序问题:
- `FileLogger` 中的 `writer` 在构造时立即初始化
- `writer` 初始化时使用了 `filename` 字段
- 但在子类 `MyWriter` 中,`filename` 被重写为 `"test.log"`
- 由于父类先于子类初始化,`writer` 初始化时 `filename` 还是 `null`
根据问题分析,解决问题
方案1:使用提前定义
代码如下:
package level02
import java.io.FileWriter
object class017 {
trait FileLogger {
val filename: String
val writer = new FileWriter(filename)
def writeLog(msg:String):Unit = {
writer.write(msg)
writer.close()
}
}
class MyWriter extends {
override val filename:String = "test.log"
}with FileLogger{
override val writer = new FileWriter(filename)
}
def main(args: Array[String]): Unit = {
val log = new MyWriter()
log.writeLog("测试内容")
}
}
成功运行
方案2:使用懒加载
代码如下:
package level02
import java.io.FileWriter
object class017 {
trait 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 = "test.log"
}
def main(args: Array[String]): Unit = {
val log = new MyWriter()
log.writeLog("测试内容")
}
}
成功运行
trait与类的区别
相同点:类和trait都可以定义成员变量(抽象,具体);继承时都使用extends关键字;
不同点:trait的构造器不能带参数;trait支持多继承;