我试图理解为什么以下代码抛出:
open class Base(open val input: String) {
lateinit var derived: String
init {
derived = input.toUpperCase() // throws!
}
}
class Sub(override val input: String) : Base(input)
Run Code Online (Sandbox Code Playgroud)
在调用此代码时,如下所示:
println(Sub("test").derived)
Run Code Online (Sandbox Code Playgroud)
它抛出一个异常,因为当时toUpperCase被调用,input解析为null.我发现这个反直觉:我将一个非null值传递给主构造函数,但是在超类的init块中它解析为null?
我想我对可能发生的事情有一个模糊的概念:因为input既可以作为构造函数参数也可以作为属性,赋值内部调用this.input,但this尚未完全初始化.这真的很奇怪:在IntelliJ调试器中,input正常解析(到值"test"),但是一旦我调用表达式评估窗口并input手动检查,它就会突然变为空.
假设这是预期的行为,你建议做什么,即当需要初始化从同一类的属性派生的字段时?
更新: 我发布了两个更简洁的代码片段,说明了混淆源自何处:
https://gist.github.com/mttkay/9fbb0ddf72f471465afc https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba
原始示例等效于以下Java程序:
class Base {
private String input;
private String derived;
Base(String input) {
this.input = input;
this.derived = getInput().toUpperCase(); // Initializes derived by calling an overridden method
}
public String getInput() {
return input;
}
}
class Derived extends Base {
private String input;
public Derived(String input) {
super(input); // Calls the superclass constructor, which tries to initialize derived
this.input = input; // Initializes the subclass field
}
@Override
public String getInput() {
return input; // Returns the value of the subclass field
}
}
Run Code Online (Sandbox Code Playgroud)
在Sub类中重写了getInput()方法,因此代码调用Sub.getInput().此时,Sub类的构造函数尚未执行,因此保存Sub.input值的后备字段仍为null.这不是Kotlin的错误; 您可以轻松地在纯Java代码中遇到同样的问题.
修复是不覆盖属性.(我已经看过你的评论,但这并没有真正解释为什么你认为你需要覆盖它.)
| 归档时间: |
|
| 查看次数: |
1294 次 |
| 最近记录: |