open class Super {
open var name : String = "Name1"
init {
println("INIT block fired with : $name")
name = name.toUpperCase()
println(name)
}
}
class SubClass(newName : String) : Super() {
override var name : String = "Mr. $newName"
}
fun main(args: Array<String>) {
var obj = SubClass("John")
println(obj.name)
}
上面的Kotlin代码导致以下TypeCastException:
INIT block fired with : null
Exception in thread "main" kotlin.TypeCastException: null cannot be cast to non-null type java.lang.String
at Super.<init>(index.kt:7)
at SubClass.<init>(index.kt:13)
at IndexKt.main(index.kt:21)
正如我对Kotlin中的类继承的理解,首先使用传递的参数调用超类的主构造函数和init块以及辅助构造函数 . 之后,子类可以使用自己的版本覆盖这些属性 .
那么为什么上面的代码导致了所描述的异常......我做错了什么...为什么超类中的init块被触发为null ... ???起初我猜测init块可能在实际属性初始化之前被触发,因为它作为主构造函数的一部分执行,但是在主构造函数中初始化name属性如下所示给出了相同的错误,IDE会警告我所以 .
open class Super(open var name : String = "Name1") {
init {
println("INIT block fired with : $name")
name = name.toUpperCase()
println(name)
}
}
class SubClass(newName : String) : Super() {
override var name : String = "Mr. $newName"
}
fun main(args: Array<String>) {
var obj = SubClass("John")
println(obj.name)
}
安慰 :
INIT block fired with : null
Exception in thread "main" kotlin.TypeCastException: null cannot be cast to non-null type java.lang.String
at Super.<init>(index.kt:5)
at Super.<init>(index.kt:1)
at SubClass.<init>(index.kt:11)
at IndexKt.main(index.kt:19)
我在这里做错了什么,或者这是一个语言错误...... ???我该怎么做才能避免错误并使init块与实际传递的值一起触发而不是null ... ???详细说明幕后发生的事情 . 这时我在实际的代码库中有类似这样的类的几种情况,我希望从另一个类继承,我想维护属性名称,因为它们......
1 回答
基本上,因为你告诉Kotlin你的子类现在将定义
name
,所以当Super
中的init
块被执行时它没有被定义 . 在初始化SubClass
之前,您将推迟定义 .此行为记录在Kotlin网站"Derived class initialization order"下:
FWIW,这类似于一些Java代码分析工具在构造函数中引用非final方法时会抱怨的原因 . 在Kotlin中解决这个问题的方法是不要在超类中的
init
块中引用open
属性 .