class C(val string: String) {
init {
println(string)
}
}
abstract class A {
abstract var string: String
val c = C(string)
}
class B : A() {
override var string = "string"
}
fun main() {
B()
}
kotlin playground for the problem
这段代码在运行时崩溃,因为字符串变量没有初始化,如何做正确的?
2条答案
按热度按时间pcww981p1#
在类的初始化中使用抽象或开放变量不是一个好的做法,也是危险的。如果您在Android Studio或IntelliJ IDEA中编写此代码,您将收到以下警告:
Accessing non-final property string in constructor
.这里发生了什么,超类
A
在完全初始化B
之前,会先被初始化,所以这行代码val c = C(string)
会在给string
赋值之前运行,这就是导致错误的原因,你会得到一个NullPointerException
,因为string
是null
。你可以使用
lazy
来初始化c,如下所示:c
只有在被调用时才被初始化,所以现在它是安全的,因为只有当B
被完全初始化时才能调用它。vc9ivgsu2#
您正在使用非final属性初始化
A
的属性-在本例中,您正在使用abstract
属性x1m3 n1 '初始化c
。这通常是不安全的。子类可以覆盖非final属性,使其在以后的时间点进行初始化,这意味着任何依赖于超类中非final属性的初始化都将得到一个未定义的值。
B
重写了string
,使其在A
的主构造函数被调用后被初始化。因此,当A
的主构造函数被运行,并且c
被初始化时,string
的值为null。要解决此问题,可以将
c
设置为lazy:这只会在你第一次访问
c
时初始化它,不管string
当时的值是什么。或者,将
c
设为已计算:这将在每次访问
c
时生成一个新的C
,当前值为string
。