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触发…… 详细说明幕后发生的事情。这时我在实际的代码库中遇到了类似这样的类,在这种情况下我想从另一个类继承,我想保持属性名称不变...
本质上,因为您告诉Kotlin您的子类现在将要定义name,所以init在Super执行块插入时未定义它。您要推迟对它的定义,直到SubClass初始化为止。
此行为记录在Kotlin网站上的“派生类初始化顺序”下:
在构造派生类的新实例期间,基类初始化作为第一步完成(仅通过对基类构造函数的参数求值),因此在派生类的初始化逻辑运行之前发生。
...
这意味着,在执行基类构造函数时,在派生类中声明或重写的属性尚未初始化。如果在基类初始化逻辑中使用了这些属性中的任何一个(直接或间接地通过另一个重写的开放成员实现),则可能导致错误的行为或运行时失败。因此,在设计基类时,应避免在构造函数,属性初始化程序和init块中使用开放成员。[强调我的]
FWIW,这类似于某些Java代码分析工具会在您引用构造函数中的非最终方法时抱怨的原因。在Kotlin中解决此问题的方法是不要在超类open的init块中引用属性。
| 归档时间: | 
 | 
| 查看次数: | 1043 次 | 
| 最近记录: |