gpt4 book ai didi

kotlin - 在 init block 中如何处理被覆盖的属性?

转载 作者:IT老高 更新时间:2023-10-28 13:46:53 25 4
gpt4 key购买 nike

我试图理解为什么会抛出以下代码:

open class Base(open val input: String) {
lateinit var derived: String

init {
derived = input.toUpperCase() // throws!
}
}

class Sub(override val input: String) : Base(input)

当像这样调用这段代码时:

println(Sub("test").derived)    

它抛出异常,因为在调用 toUpperCase 时,input 解析为 null。我发现这个反直觉:我将一个非空值传递给主构造函数,但在父类(super class)的 init block 中它解析为空?

我想我对可能发生的事情有一个模糊的想法:由于 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
}
}

getInput() 方法在 Sub 类中被重写,因此代码调用 Sub.getInput()。此时,Sub 类的构造函数还没有执行,所以保存 Sub.input 值的后备字段仍然为空。这不是 Kotlin 中的错误;在纯 Java 代码中很容易遇到同样的问题。

解决方法是不覆盖该属性。 (我看过你的评论,但这并不能真正解释为什么你认为你需要覆盖它。)

关于kotlin - 在 init block 中如何处理被覆盖的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34697222/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com