为什么我们应该避免使用基类的开放成员?

时间:2019-02-09 04:51:17

标签: kotlin

在我阅读Kotlin的document时,我发现我们应该避免使用在基类上声明的open属性:

  

这意味着,在执行基类构造函数时,在派生类中声明或重写的属性尚未初始化。如果在基类初始化逻辑中使用了这些属性中的任何一个(直接或间接地,通过另一个重写的开放成员实现),则可能导致错误的行为或运行时失败。因此,在设计基类时,应避免在构造函数,属性初始化程序和init块中使用开放成员。

文档说,当调用基类的构造函数时,派生类中的属性尚未初始化。但是,我们如何从基类构造函数中访问未初始化的派生类的属性(我假设incorrect behavior or a runtime failure是由这种情况引起的)?有可能吗?

2 个答案:

答案 0 :(得分:2)

我不了解kotlin,但我假设open与其他语言中的virtual相同。在基类构造函数中调用虚拟成员是不安全的,因为在派生构造函数之前调用了基构造函数。如果重写属性要求对派生类进行完全初始化,则可能会导致错误,因为当您位于基本构造函数内部时,尚未调用派生构造函数。至少那是它在C#等.NET语言中的工作方式。

答案 1 :(得分:1)

Kotlin中的打开函数是可以被子类覆盖的函数。通常,限制类的继承是一个好习惯,因为您应该为类提供必要的代码以使其可重写。如果您的目的不是让一个类覆盖您的基类,那么您应该将其定型。因此Kotlin通过将每个类和方法默认设置为final来简化此过程。您可以在《 Kotlin in Action》一书的“对象和类”一章中找到更详细的答案。

  

修改基类时会发生所谓的脆弱基类问题   可能导致子类的错误行为,因为基类no的更改代码   与其子类中的假设匹配。如果课程没有提供确切的规则   关于应该如何子类化(应该重写哪些方法以及如何重写),   客户有以基类作者的方式重写方法的风险   没想到由于无法分析所有子类,因此基类为   从某种意义上讲,“脆弱”可能会导致行为的意外改变   子类。   为避免出现此问题,Joshua Bloch(Addison-Wesley,   (2008年)是有关Java良好编程风格的最著名书籍之一,建议您   您“设计和记录继承文件,否则禁止继承”。这意味着所有课程和   不是专门要在子类中覆盖的方法   明确标记为final。   Kotlin遵循相同的哲学。 Java的类和方法由   默认情况下,科特林默认为最终版本。