当您声明 aval
时,会发生几件事:
- 编译器确保在初始化类的实例时为变量分配足够的空间
- 一个访问器方法被创建
- 创建设置变量初始值的初始化程序。
你的代码
abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }
class B extends A { val aSet = Set(4,5,6) }
new B()
大致相当于
abstract class A {
private var aSet_A: Set[Int] = null
def aSet: Set[Int] = aSet_A
require(aSet.contains(3))
}
class B extends A {
private var aSet_B: Set[Int] = Set(4,5,6)
override def aSet: Set[Int] = aSet_B
}
new B()
因此,会发生以下情况:
aSet_A
为和分配内存aSet_B
并设置为null
。
- 的初始化
A
程序正在运行。
require
onaSet.contains(3)
被调用
- 由于
aSet
在 中被覆盖B
,它返回aSet_B
。
- 因为
aSet_B
is null
,所以抛出一个 NPE。
为避免这种情况,您可以将其实现aSet
为惰性变量:
abstract class A {
def aSet: Set[Int]
require(aSet.contains(3))
}
class B extends A {
lazy val aSet = Set(4,5,6)
}
new B()
这会引发requirement failed
异常:
java.lang.IllegalArgumentException: requirement failed
Scala 常见问题解答的必填链接:
相关问题列表:
- 为什么使用val实现抽象方法并在val表达式中从超类调用返回NullPointerException
- 运行覆盖值的父代码,但未在父处分配值