scala - 初始化顺序在惰性 val 访问时抛出空指针
问题描述
预期,以下没有惰性 val 的初始化顺序会引发空指针异常
class Foo {
Bar.x // NullPointerException
}
object Bar extends Foo {
val x = 42
}
object Hello extends App {
Bar
}
检查-Xprint:jvm
输出并引用@paradigmatic answer,我们看到这是由于' 的构造函数首先运行并且在 ' 的构造函数中初始化之前Foo
调用:Bar.x()
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
时也会抛出空指针
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
警卫,它应该可以工作
<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
什么时候lazy val x
呢?
解决方案
我认为这个 NPE 根本不相关val
。检查这个:
class Foo {
Bar.anyMethod
}
object Bar extends Foo {
def anyMethod = ???
}
object Hello extends App {
Bar
}
//java.lang.NullPointerException
Foo
正在尝试在仍在建设中Bar
时运行构造函数。Bar
所以这也是你Foo
在打电话之前正在做的事情x
。
顺便说一句,如果您将所有内容都放入Hello
withmain
方法中,那么在我和您的情况下,您将获得 StackOverflow 而不是 NPE。
object Hello {
def main(args: Array[String]): Unit = {
class Foo {
Bar.anyMethod
}
object Bar extends Foo { //<- Bar is like local val now instead of field
def anyMethod= ??? // of package object, so stack is available now.
}
Bar
}
}
推荐阅读
- r - 将一条线拟合到热图
- java - 如何在 Java 代码中使用 Scala 注释
- wix - WiX - VS 架构和 Visual Studio 2019
- caching - 如何更改 Flutter 中图像缓存的缓存时长(包:flutter_cached_network_image & flutter_cache_manager)
- ruby - Ruby:“创建和增加”的成语
- javascript - Sharepoint 2010 中与 ListData.svc 一起使用的列表名称的规则
- jmh - 带有字符串参数的 JMH-Benchmark 方法
- .net - 看不懂这段点网代码
- android - 无法在密码提示 Android Studio 中使用自定义字体
- ruby-on-rails - 数组字段在 rails form_for 中两次发送值