运行下面的代码:
class Parent {
val value = {
println("Setting value in parent")
"ParentVal"
}
println(s"Parent value is ${value}")
}
class Child extends Parent {
override val value = {
println("Setting value in child")
"ChildVal"
}
println(s"Child value is ${value}")
}
new Child
生成以下输出:
Setting value in parent
Parent value is null
Setting value in child
Child value is ChildVal
因此,运行与父值赋值关联的代码,但是值并未真正在父值赋值处赋值。之后,子代码运行并按预期分配值。
有人可以在较低的层面上解释这里的事件链吗?
您可以将val
视为没有setter的私有成员变量+getter方法的组合。如果你在没有val
s 的情况下重写代码,它将是这样的:
class Parent {
private[this] var parentValue = {
println("Setting value in parent")
"ParentVal"
}
def value: String = parentValue
println(s"Parent value is ${value}")
}
class Child extends Parent {
private[this] var childValue = {
println("Setting value in child")
"ChildVal"
}
override def value = childValue
println(s"Child value is ${value}")
}
new Child
就像原版一样,它打印:
Setting value in parent
Parent value is null
Setting value in child
Child value is ChildVal
这是因为父构造函数调用方法value
,但此方法被def value = childValue
覆盖。返回的childValue
是null
的,因为当调用父构造函数时,子构造函数尚未被调用。
您可以在此处阅读有关对象初始化顺序的更多信息。
相关答案:
为什么在 val 表达式中使用 val 和从超类调用实现抽象方法会返回 NullPointerException。
在抽象超类中使用
require
断言创建 NPE