kotlin父类的var依赖于抽象的var


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 problem

这个代码崩溃在运行时由于字符串var未初始化,如何做正确的?

在类的初始化中使用抽象变量或开放变量不是一个好的做法,而且很危险。如果你在Android Studio或IntelliJ IDEA中编写这段代码,你会得到这样的警告:Accessing non-final property string in constructor.

这里发生了什么?在完全初始化B之前,超类A将首先被初始化,因此val c = C(string)这行代码将在给string赋值之前运行,这就是导致错误的原因,您将得到NullPointerException,因为stringnull

如何解决这个问题?你可以使用lazy像这样初始化c:

val c by lazy { C(string) }

现在c不会被初始化只有当你调用它,所以现在它是安全的因为只有在B完全初始化时才能调用它

您正在使用非final属性初始化A的属性-在本例中,您正在使用abstract属性string初始化c

abstract var string: String
val c = C(string)

这通常是不安全的。子类可以覆盖非final属性,这样它就可以在稍后初始化,这意味着任何依赖于超类中的非final属性的初始化都将得到一个未定义的值。

在这种情况下,这正是所发生的。B覆盖string,因此在A的主构造函数被调用之后,它被初始化。因此,当A的主构造函数运行时,c被初始化,string的值为null。

要解决这个问题,您可以将c设置为lazy:

val c by lazy { C(string) }

这只会在你第一次访问c时初始化它,不管string的值是多少。

或者,让ccomputed:

val c get() = C(string)

这将在每次访问c时生成一个新的C,当前值为string

最新更新