预期,以下没有惰性 val 的初始化顺序会抛出空指针异常
class Foo {
Bar.x // NullPointerException
}
object Bar extends Foo {
val x = 42
}
object Hello extends App {
Bar
}
正在检查-Xprint:jvm
输出,并引用@paradigmaticanswer https://stackoverflow.com/a/12185848/5205022,我们看到这是由于Foo
的构造函数首先运行并调用Bar.x()
before Bar.this.x
初始化于Bar
的构造函数:
class Foo extends Object {
def <init>(): example.Foo = {
Foo.super.<init>();
Bar.x();
()
}
};
object Bar extends example.Foo {
private[this] val x: Int = _;
<stable> <accessor> def x(): Int = Bar.this.x;
def <init>(): example.Bar.type = {
Bar.super.<init>();
Bar.this.x = 42;
()
}
};
但是,为什么也会抛出空指针x
is lazy https://docs.scala-lang.org/tutorials/FAQ/initialization-order.html#use-lazy-vals like so
object Bar extends Foo {
lazy val x = 42
}
分析-Xprint:jvm
在惰性情况下的输出我们有
class Foo extends Object {
def <init>(): example.Foo = {
Foo.super.<init>();
Bar.x();
()
}
};
object Bar extends example.Foo {
final <synthetic> lazy private[this] var x: Int = _;
@volatile private[this] var bitmap$0: Boolean = _;
private def x$lzycompute(): Int = {
Bar.this.synchronized(if (Bar.this.bitmap$0.unary_!())
{
Bar.this.x = (42: Int);
Bar.this.bitmap$0 = true
});
Bar.this.x
};
<stable> <accessor> lazy def x(): Int = if (Bar.this.bitmap$0.unary_!())
Bar.this.x$lzycompute()
else
Bar.this.x;
def <init>(): example.Bar.type = {
Bar.super.<init>();
()
}
};
在我看来它应该起作用,因为bitmap$0
guard
<stable> <accessor> lazy def x(): Int = if (Bar.this.bitmap$0.unary_!())
Bar.this.x$lzycompute()
else
Bar.this.x;
运行时字段访问器检查-Xcheckinit
似乎对我的机器上的 Scala 2.12.8 感到满意,所以为什么NullPointerException
when lazy val x
?