为啥 Kotlin 类默认是 final 而不是 open?

Posted

技术标签:

【中文标题】为啥 Kotlin 类默认是 final 而不是 open?【英文标题】:Why are Kotlin classes final by default instead of open?为什么 Kotlin 类默认是 final 而不是 open? 【发布时间】:2019-01-11 18:47:18 【问题描述】:

文档告诉我们关于open注解的以下内容:

类上的 open 注解与 Java 的 final 相反:它 允许其他人从这个类继承。默认情况下,所有类 Kotlin 是final,对应Effective Java, 3rd Edition, 第 19 条:设计和记录继承或禁止继承。

我的课

class Foo //I can't inherit it
open class Bar //I can inherit it

默认保留所有类final的真正动机是什么?性能有什么提升吗?还是只是一种设计模式?为什么默认禁止open

【问题讨论】:

您应该阅读 Effective Java 项目。它描述了为继承设计一个类需要多少工作。 极度痛苦的工作量。记录您对子类的所有要求,以及您要求他们不要做的所有事情。构建至少 3 个单独的子类,以验证您的基类实际上是有用的(哦,您不能自己编写这些类;必须由其他人编写,因为您会作弊)。等等等等等等。 大多数类应该是最终的。扩展它们可能是个坏主意。 【参考方案1】:

对我来说有两个原因:

首先,Kotlin 从函数式编程世界中汲取了许多想法,并尽可能频繁地使用不变性来避免所有 known problems with mutation。

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

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

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

我想到的第二个想法是继承经常被误用。 一些常见陷阱的例子解释了here

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

但只要没有 kotlin 开发者的官方声明,我只能给出一个固执己见的答案。

【讨论】:

【参考方案2】:

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

正如已经记录的那样,设计师遵循Joshua Bloch's Effective Java,其中在类和接口一章中谈到了其中一个原则

设计和记录继承或禁止它

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

假设我们有,

class Foo 

我们(即使是此代码的非作者) 确信此 class Foo 对任何扩展都是关闭的,并且没有随机类正在使用它,这也是通过查看它的签名。相比之下,Java 类则不能这样说,除非声明为 final,否则某些悬空子类仍然可以扩展它。

另一方面,

open class Foo

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

【讨论】:

如果你是 S.O.L.I.D.人,这似乎是在面对Open for Extension的飞行。我发现期末课程非常令人沮丧,尤其是在图书馆中。如果存在错误或者您想扩展它们,这会使过程变得非常复杂。编写良好的库具有内置的可扩展性,但没有人知道未来会怎样或如何使用库。【参考方案3】:

在默认情况下使类 final 可以在运行时使用更少的内存。

【讨论】:

【参考方案4】:

我能想到的另一个原因是 final 使静态调度优化成为可能,这意味着它不需要进行方法表查找。

【讨论】:

以上是关于为啥 Kotlin 类默认是 final 而不是 open?的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 初学者类的修饰符

JAVA,为啥final类不能被继承,如果定义为final的类该类里面成员变量不特殊说明则是final类还是非final

在Kotlin上怎样用Mockito2 mock final 类(KAD 23)

为啥使用 NSError 间接参数而不是 @try/@catch/@finally

kotlin学习之类的修饰符与抽象类,嵌套类,内部类,匿名内部类

Kotlin与Java的异同