为什么 Kotlin 类默认是 final 而不是 open ?

Abn*_*cio 5 java performance inheritance design-patterns kotlin

该文档告诉我们有关open注释的以下内容:

类上的开放注解与 Java 的最终注解相反:它允许其他人从这个类继承。默认情况下,Kotlin 中的所有类都是 final 的,这对应Effective Java,第 3 版,第 19 条:继承的设计和文档,否则禁止它。

我的课程

class Foo //I can't inherit it
open class Bar //I can inherit it
Run Code Online (Sandbox Code Playgroud)

final默认情况下保留所有类的真正动机是什么?有没有性能上的提升?或者只是一种设计模式?为什么open默认禁止?

dev*_*Lui 7

对我来说有两个原因:

首先,Kotlin 从函数式编程世界中汲取了许多想法,并尽可能多地使用不变性来避免所有已知的变异问题

因此,默认情况下将每个类声明为“final”(至少对我而言)是相似的。

在运行时不能更改或更改类(使用反射之类的东西),这会使 Kotlin 编译器的安全检查无用。

所以如果你想“改变”一个类的默认实现,你必须明确地将它标记为打开。

我想到的第二个想法是继承经常被滥用。解释了一些常见陷阱的示例此处了

有一个原则“优先组合而不是继承”作为更好设计的指导方针。因此,默认情况下将每个类声明为 final 迫使开发人员至少停下来考虑解决问题的替代方法,而不是出于错误的原因使用继承。

但只要 kotlin 开发人员没有官方声明,我只能给出一个自以为是的答案。

  • 不可变实例和不可变类之间存在差异。虽然您可能会避免一些不好的做法,但它会阻止重用;确实如此,尤其是在考虑原始开发人员未想到的场景时,但如果实施得当,这仍然可以工作 (2认同)

iCa*_*ntC 5

Kotlin 设计师只是想确保每个人都遵循良好的实践。

正如已经记录的那样,设计者遵循Joshua Bloch 的 《Effective Java》,其中在“类和接口”一章中谈到了原则之一

继承的设计和文档,否则禁止继承

它提倡在使用任何继承行为之前明确记录它的想法。

假设我们有,

class Foo 
Run Code Online (Sandbox Code Playgroud)

我们(甚至是该代码的非作者)确信这class Foo对于任何扩展都是关闭的,并且没有随机类正在使用它,这也只是通过看到它的签名来实现。相反,对于Java类则不能这样说,除非声明final,否则某些悬空子类仍然可以扩展它。

另一方面,

open class Foo
Run Code Online (Sandbox Code Playgroud)

仅通过类签名,我们就知道该类是开放继承的,并且可能有多个类覆盖其行为。如您所见,继承在这里被明确记录

  • 如果你是一个坚定的人,这似乎与开放扩展背道而驰。我发现期末课程非常令人沮丧,尤其是在图书馆。如果存在错误或者您想扩展它们,那么过程就会变得非常复杂。一个编写良好的库具有内置的可扩展性,但没有人知道未来会怎样或如何使用库。 (6认同)

Dun*_*een 5

对于那些熟悉 SOLID 的“O”的人来说,这似乎是一个奇怪的选择。不变性与继承无关!因此,在java中将一个类标记为final并不能防止该类的实例状态发生变化(当然,您可以将所有字段(以及字段的字段!)标记为final - 叹息)。

模块化的本质是能够以新的、有用的和可能意想不到的方式重新部署现有类型。实现此目的的一种方法是通过继承。继承和多态性(根本不是一回事)在 Java 社区中已经失宠,因为遵守里氏替换原则(“L”)很困难。到处违反 Liskov 规则的大型系统更难以推理。锁定类和函数以防止不良继承和覆盖是“把婴儿和洗澡水一起倒掉”。您在表面上获得的安全性远大于在模块化和灵活性方面的损失。

类,默认情况下应该是开放扩展的。