我需要计算硬编码图像的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
答案 0 :(得分:1)
我认为关键的区别在于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
提供适当的值。
documentation中对此有更详细的说明:
在设计基类时,因此应避免使用open 构造函数,属性初始化器和init块中的成员。
(master
属性是abstract
,表示它是open
。)