Kotlin 例外情况“初始化错误”;指定为非空的参数为空";抽象类

Kotlin 例外情况“初始化错误”;指定为非空的参数为空";抽象类,kotlin,lazy-initialization,Kotlin,Lazy Initialization,我需要计算硬编码图像的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

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()
        }
    }
}
例外情况:

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)
删除
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()
        }
    }
}
抽象类ImageData{
摘要val主机:列表
//是的,我知道'get()'是不必要的,但由于某种奇怪的原因,它导致'hash'崩溃。
val数据:Iterable get()=master.map{s->hex(s)}
val hash:Int by lazy{
master.fold(0){hash,s->
31*hash+s.hashCode()
}
}
}
似乎解决了问题-不知道为什么

Kotlin版本
最新稳定版(1.3)


目标JVM版本:
1.6

我认为关键区别在于
get()
data
属性上,再加上
master
是抽象的。当构造这个基类时(在创建子类之前,因为子类的构造函数必须先调用超类的构造函数),基类初始化其所有成员。您的原始代码有以下行:

val data: Iterable<HexString> = master.map { s -> hex(s) }
val数据:Iterable=master.map{s->hex(s)}
这将获取master的值,此时该值为null,因为具体的子类尚未创建,因此无法重写该属性

在更新的代码段中,您有以下内容:

val data: Iterable<HexString> get() = master.map { s -> hex(s) }
val数据:Iterable get()=master.map{s->hex(s)}
在初始化抽象基类期间,
data
属性现在不需要初始化(使用
master
的值)。相反,当在运行时调用
data
属性时,将执行
get
函数。到那时,已经构造了具体的子类,可以为
master
提供适当的值

有关这方面的更多详细信息,请参见:

因此,在设计基类时,应该避免使用open 构造函数、属性初始值设定项和init块中的成员


master
属性是
abstract
,这意味着它是
打开的

有趣。。。但当
数据
被初始化时,这个问题不会发生吗?在这里,当请求
散列时,异常会发生在运行时。真的吗?有趣的我刚刚尝试了您的原始代码,并且在我的测试代码中的这一行中使用了
FooImageData
后立即得到异常:
val x=FooImageData
(即在我调用
hash
之前)。你能分享显示它出错的完整代码吗?事实上,我认为你的错误堆栈跟踪也显示它在构造过程中发生:
在…FooImageData.(FooImageData.kt:3)
(注意这里的
init
函数,即在
FooImageData
的初始化过程中).哦,我明白了-它在最后一分钟创建对象。
val data: Iterable<HexString> = master.map { s -> hex(s) }
val data: Iterable<HexString> get() = master.map { s -> hex(s) }