当前位置:  开发笔记 > 开发工具 > 正文

如何在init块中处理重写属性?

如何解决《如何在init块中处理重写属性?》经验,为你挑选了1个好方法。

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

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.我发现这个反直觉:我将一个非null值传递给主构造函数,但是在超类的init块中它解析为null?

我想我对可能发生的事情有一个模糊的概念:因为input既可以作为构造函数参数也可以作为属性,赋值内部调用this.input,但this尚未完全初始化.这真的很奇怪:在IntelliJ调试器中,input正常解析(到值"test"),但是一旦我调用表达式评估窗口并input手动检查,它就会突然变为空.

假设这是预期的行为,你建议做什么,即当需要初始化从同一类的属性派生的字段时?

更新: 我发布了两个更简洁的代码片段,说明了混淆源自何处:

https://gist.github.com/mttkay/9fbb0ddf72f471465afc https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba



1> yole..:

原始示例等效于以下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
    }
}

在Sub类中重写了getInput()方法,因此代码调用Sub.getInput().此时,Sub类的构造函数尚未执行,因此保存Sub.input值的后备字段仍为null.这不是Kotlin的错误; 您可以轻松地在纯Java代码中遇到同样的问题.

修复是不覆盖属性.(我已经看过你的评论,但这并没有真正解释为什么你认为你需要覆盖它.)

推荐阅读
牛尾巴2010
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有