kotlin - ExceptionInInitializerError“指定为非空的参数为空”与抽象类
问题描述
我需要计算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()
}
}
}
似乎解决了这个问题 - 不知道为什么。
Kotlin 版本Latest stable (1.3)
目标 JVM 版本:1.6
解决方案
我认为关键的区别在于get()
属性,以及抽象data
的事实。master
当这个基类被构造时(在创建子类之前,因为子类的构造函数必须先调用超类的构造函数),基类初始化它的所有成员。您的原始代码有这一行:
val data: Iterable<HexString> = master.map { s -> hex(s) }
这将获取 master 的值,此时它为 null,因为尚未创建具体的子类,因此还不能覆盖该属性。
在您更新的代码段中,您有以下内容:
val data: Iterable<HexString> get() = master.map { s -> hex(s) }
在抽象基类的初始化过程中,data
现在不需要初始化该属性(使用 的值)。master
相反,当data
在运行时调用该属性时,该get
函数将被执行。到那时,具体的子类已经构建并且可以为master
.
文档中有更多详细信息,其中说:
因此,在设计基类时,应避免在构造函数、属性初始值设定项和 init 块中使用开放成员。
(master
属性是abstract
,这意味着它是open
。)
推荐阅读
- windows - 如何通过具有“受限命名空间”的 UWP 应用程序的“Windows 应用程序认证工具包 - 测试”?
- selenium - 在测试自动化中是否使用 Select 元素而不是物理上执行“element.click()”的坏习惯?
- pandas - Dask数据框:获取每个排序组的第一行
- javascript - 查找仅在 array1 javascript 中可用的对象
- r - 按组在 tidymodels 中应用步骤程序
- typescript - `!.` 运算符在打字稿中的含义是什么?
- sql - where 条件为 varchar 使用变量
- go - 在 vscode 编辑器中格式化 go 代码的问题
- validation - 训练不能很好地泛化来预测验证和测试集,如何提高泛化能力?
- c++ - 什么是残环?