我最近被告知面向对象编程的一个好习惯,你应该总是允许继承你的类。我真的不这么认为,但我没有坚定的理由。
真实世界阻止继承的示例:
final
类修饰符适用于许多标准组件,例如java.lang.String
。可能的原因我认为:
所以我的问题是:我应该在什么情况下故意阻止继承?
答案 0 :(得分:4)
对于初学者来说,如果你是积极的,那么只允许继承你不希望别人扩展你的班级。通常不建议出于微不足道的原因(例如性能)来防止继承,因为代码重用通常会超过通过标记类final
可以实现的小的性能提升。
话虽如此,这里有几个例子,你可能想要明确地阻止继承:
您正在编写一个商业的闭源类,并且您不希望人们能够更改功能。这是防止类继承的一个很好的理由,因为如果人们已经覆盖了你的方法和/或扩展你的类,并且抱怨他们得到了意想不到的结果,你不希望以后必须支持它。
您正在设计一个不可变类。通过标记类final
,您可以防止子类破坏类的不可变行为。例如,如果允许您继承String
,则其他人可以创建允许String
修改的自己的实现。现在,没有采用类型String
的代码可以确定该对象是不可变的。
您想强制composition over inheritance。当你想要避免类之间的紧密耦合时(即你不希望彼此高度依赖的类组),这是可取的。
您希望鼓励编译器进行内联。将类和方法标记为final可能会导致性能提升,因为它将确保Java不必在运行时查找正确的类方法来调用对象。非final方法被标记为虚拟,以便在需要时可以正确扩展它们,最终方法可以在类中直接链接或编译。请注意,通过这样做可以获得的性能提升通常是微不足道的(特别是如果您的课程方法很大)。
答案 1 :(得分:3)
事实上,我试图遵循的做法,以及Josh Bloch在他的 Effective Java 一书中推荐的做法,正好与你被告知的做法相反:除非你已经考虑了继承,设计了你的类继承,并记录了你的类必须如何继承,你应该总是禁用继承。
我建议您阅读有效Java的这一章(您不会后悔购买它),并将其展示给告诉您有关此规则的人。
不允许继承的最明显原因是不变性。不可变对象易于使用(只有一个状态),可以缓存,在许多对象之间共享,并且本质上是线程安全的。如果该类是可继承的,那么任何人都可以通过添加可变属性来扩展该类并使其可变。
答案 2 :(得分:3)
这是我的0.02 ......
允许人们在课堂上继承可以解决无法预料的问题。 (例如,经常出现在RoR中的monkeypatching。它可能是丑陋的,但它是现实与迂腐)。话虽如此,我不是无偿继承的忠实粉丝。基类和子类之间的关系可能很脆弱。深层继承层次结构很难理解。
我认为不允许继承的一个案例是强制执行不变性。这对Java String类很重要。