ExceptionInInitializerError "Parameter specified as non-null is null" with abstract class
ExceptionInInitializerError "Parameter specified as non-null is null" with abstract class
我需要计算硬编码图像的hash
。
abstract class ImageData {
protected abstract val master: List<String>
val data: Iterable<HexString> = master.map { s -> hex(s) }
val hash: Int by lazy {
master.fold(0) { hash, s ->
31 * hash + s.hashCode()
}
}
}
示例图片。
object FooImageData : ImageData() {
override val master = listOf(
"424d3684030000000000..."
// ...
)
}
异常:
java.lang.ExceptionInInitializerError
at ....updateGraphics(Graphics.kt:162)
...
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter $this$collectionSizeOrDefault
at kotlin.collections.CollectionsKt__IterablesKt.collectionSizeOrDefault(Iterables.kt)
at ....ImageData.<init>(ImageData.kt:17)
at ....FooImageData.<init>(FooImageData.kt:3)
at ....FooImageData.<clinit>(FooImageData.kt:3)
at ....updateGraphics(Graphics.kt:162)
在 ....updateGraphics(Graphics.kt:162)
是:
private suspend fun updateGraphics(...) {
val hash = (FooImageData.hash * 31 + BarImageData.hash)
删除 lazy
并没有解决问题。
所有研究都表明参数的排序可能是个问题,但这里似乎并非如此 - 或者是这样吗?
使用:
abstract class ImageData {
abstract val master: List<String>
// Yes I know the `get()` is unnecessary but for some weird reason that causes `hash` to crash.
val data: Iterable<HexString> get() = master.map { s -> hex(s) }
val hash: Int by lazy {
master.fold(0) { hash, s ->
31 * hash + s.hashCode()
}
}
}
似乎解决了问题 - 不知道为什么。
科特林版本Latest stable (1.3)
目标 JVM 版本:1.6
我认为关键区别在于 data
属性 上的 get()
,同时 master
是抽象的。当构造此基 class 时(即 在 之前创建子 class,因为子class 的构造函数必须调用超class 的构造函数优先),基 class 初始化它的所有成员。您的原始代码有这一行:
val data: Iterable<HexString> = master.map { s -> hex(s) }
这会获取 master 的值,此时它为 null,因为具体的 subclass 尚未创建,因此还不能覆盖 属性。
在您更新的代码段中,您有:
val data: Iterable<HexString> get() = master.map { s -> hex(s) }
data
属性 现在不需要在初始化抽象基 class 期间初始化(使用 master
的值)。相反,当 data
属性 在运行时被调用时, get
函数将被执行。到那时,具体的subclass已经构建完成,可以为master
.
提供一个合适的值
documentation 中对此有更多详细信息,它说:
When designing a base class, you should therefore avoid using open
members in the constructors, property initializers, and init blocks.
(master
属性是abstract
,意思是open
。)
我需要计算硬编码图像的hash
。
abstract class ImageData {
protected abstract val master: List<String>
val data: Iterable<HexString> = master.map { s -> hex(s) }
val hash: Int by lazy {
master.fold(0) { hash, s ->
31 * hash + s.hashCode()
}
}
}
示例图片。
object FooImageData : ImageData() {
override val master = listOf(
"424d3684030000000000..."
// ...
)
}
异常:
java.lang.ExceptionInInitializerError
at ....updateGraphics(Graphics.kt:162)
...
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter $this$collectionSizeOrDefault
at kotlin.collections.CollectionsKt__IterablesKt.collectionSizeOrDefault(Iterables.kt)
at ....ImageData.<init>(ImageData.kt:17)
at ....FooImageData.<init>(FooImageData.kt:3)
at ....FooImageData.<clinit>(FooImageData.kt:3)
at ....updateGraphics(Graphics.kt:162)
在 ....updateGraphics(Graphics.kt:162)
是:
private suspend fun updateGraphics(...) {
val hash = (FooImageData.hash * 31 + BarImageData.hash)
删除 lazy
并没有解决问题。
所有研究都表明参数的排序可能是个问题,但这里似乎并非如此 - 或者是这样吗?
使用:
abstract class ImageData {
abstract val master: List<String>
// Yes I know the `get()` is unnecessary but for some weird reason that causes `hash` to crash.
val data: Iterable<HexString> get() = master.map { s -> hex(s) }
val hash: Int by lazy {
master.fold(0) { hash, s ->
31 * hash + s.hashCode()
}
}
}
似乎解决了问题 - 不知道为什么。
科特林版本Latest stable (1.3)
目标 JVM 版本:1.6
我认为关键区别在于 data
属性 上的 get()
,同时 master
是抽象的。当构造此基 class 时(即 在 之前创建子 class,因为子class 的构造函数必须调用超class 的构造函数优先),基 class 初始化它的所有成员。您的原始代码有这一行:
val data: Iterable<HexString> = master.map { s -> hex(s) }
这会获取 master 的值,此时它为 null,因为具体的 subclass 尚未创建,因此还不能覆盖 属性。
在您更新的代码段中,您有:
val data: Iterable<HexString> get() = master.map { s -> hex(s) }
data
属性 现在不需要在初始化抽象基 class 期间初始化(使用 master
的值)。相反,当 data
属性 在运行时被调用时, get
函数将被执行。到那时,具体的subclass已经构建完成,可以为master
.
documentation 中对此有更多详细信息,它说:
When designing a base class, you should therefore avoid using open members in the constructors, property initializers, and init blocks.
(master
属性是abstract
,意思是open
。)