最终和密封的目的
为什么有人想将一个类标记为最终类或密封类?
Why would anyone want to mark a class as final or sealed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为什么有人想将一个类标记为最终类或密封类?
Why would anyone want to mark a class as final or sealed?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(3)
根据维基百科,“密封类主要用于防止派生。它们在编译时添加另一个严格级别,提高内存使用率,并触发某些优化来提高运行时效率。”
另外,来自 Patrick Smacchia 的博客:
这些都是很好的理由 - 我实际上不知道性能优势的影响,直到我刚才查看:)
版本控制和安全点似乎在代码信心方面具有巨大的优势,这对于任何类型的大型项目都是非常合理的。当然,它不能直接用于单元测试,但它会有所帮助。
According to Wikipedia, "Sealed classes are primarily used to prevent derivation. They add another level of strictness during compile-time, improve memory usage, and trigger certain optimizations that improve run-time efficiency."
Also, from Patrick Smacchia's blog:
Those are all pretty good reasons - I actually wasn't aware of the performance benefit implications until I looked it up just now :)
The versioning and security points seem like a huge benefit in terms of code confidence, which is very well justified on any kind of large project. It's no drop-in for unit testing, of course, but it would help.
因为创建继承类型比大多数人想象的要困难得多。最好默认情况下以这种方式标记所有类型,因为这将防止其他人继承从未打算扩展的类型。
类型是否应该扩展是由创建它的开发人员决定的,而不是后来出现并想要扩展它的开发人员的决定。
Because creating a type for inheritance is much harder work than most folks think. It is best to mark all types this way by default as this will prevent others from inheriting from a type that was never intended to be extended.
Whether or not a type should be extended is a decision of the developer who created it, not the developer who comes along later and wants to extend it.
Joshua Bloch 在他的《Effective Java》一书中谈到了这一点。他说“继承文件或禁止继承”。
重点是,类是作者和客户之间的一种契约。允许客户端从基类继承使得这个契约更加严格。如果你要继承它,你很可能会重写一些方法,否则你可以用组合代替继承。哪些方法允许被重写,以及你必须做什么来实现它们 - 应该记录下来,否则你的代码可能会导致不可预测的结果。据我记得,他展示了这样的例子 - 这是一个带有方法的集合类,
有一些实现,即 ArrayList。现在您想要继承它并重写一些方法,以便在添加元素时它会打印以控制台消息。现在,您需要重写 add 和 addAll,还是只重写 add?这取决于 addAll 的实现方式 - 它是直接处理内部状态(如 ArrayList 那样)还是调用 add (如 AbstractCollection 那样)。或者可能有addInternal,它被add和addAll调用。直到您决定从该类继承之前,不存在此类问题。如果你只是使用它 - 它不会打扰你。因此,如果该类的作者希望您继承他的类,则必须对其进行记录。
如果他将来想改变实施方式怎么办?如果他的类仅被使用,从不继承,那么没有什么可以阻止他改变实现以提高效率。现在,如果您从该类继承,查看源代码并发现 addAll 调用 add,则您仅重写 add。后来作者更改了实现,因此 addAll 不再调用 add - 您的程序已损坏,调用 addAll 时不会打印消息。或者您查看源代码,发现 addAll 没有调用 add,因此您重写了 add 和 addAll。现在作者更改了实现,因此 addAll 调用 add - 您的程序再次被破坏,当调用 addAll 时,每个元素都会打印两次消息。
因此,如果您希望继承您的类,则需要记录如何继承。如果您认为将来可能需要更改某些可能会破坏某些子类的内容 - 您需要考虑如何避免它。通过让您的客户从您的类继承,您可以公开更多的内部实现细节,而您只是让他们使用您的类时所做的事情 - 您公开了内部工作流程,这通常会在未来版本中发生变化。
如果您公开了一些细节并且客户依赖它们 - 您将无法再更改它们。如果您同意,或者您记录了哪些内容可以被覆盖,哪些内容不能被覆盖 - 那就可以了。有时你只是不想要它。有时你只想说 - “只使用这个类,永远不要继承它,因为我想要自由地更改内部实现细节”。
所以基本上评论“因为班级不想有任何孩子,我们应该尊重它的意愿”是正确的。
因此,当有人认为可能的实现细节更改比继承更有价值时,他想将一个类标记为final/sealed。还有其他方法可以实现类似于继承的结果。
Joshua Bloch in his book Effective Java talks about it. He says "document for inheritance or disallow it".
The point is that class is sort of a contract between author and client. Allowing client to inherit from base class makes this contract much more strict. If you are going to inherit from it, you most likely are going to override some methods, otherwise you can replace inheritance with composition. Which methods are allowed to be overridden, and what you have to do implementing them - should be documented, or your code can lead to unpredictable results. As far as I remember, he shows such example - here is a collection class with methods
There is some implementation, i.e. ArrayList. Now you want to inherit from it and override some methods, so it prints to console a message when element is added. Now, do you need to override both add and addAll, or only add? It depends on how addAll is implemented - does it work with internal state directly (as ArrayList does) or calls add (as AbstractCollection does). Or may be there is addInternal, which is called by both add and addAll. There were no such questions until you decided to inherit from this class. If you just use it - it does not bother you. So the author of the class has to document it, if he wants you to inherit from his class.
And what if he wants to change the implementation in the future? If his class is only used, never inherited from, nothing stops him from changing implementation to more efficient. Now, if you inherited from that class, looked at source and found that addAll calls add, you override only add. Later author changes implementation so addAll no longer calls add - your program is broken, message is not printed when addAll is called. Or you looked at source and found that addAll does not call add, so you override add and addAll. Now author changes implementation, so addAll calls add - your program is broken again, when addAll is called message is printed twice for each element.
So - if you want your class to be inherited from, you need to document how. If you think that you may need to change something in the future that may break some subclasses - you need to think how to avoid it. By letting your clients inherit from your class you expose much more of internal implementation details that you do when you just let them use your class - you expose internal workflow, that is often subject to changes in future versions.
If you expose some details and clients rely on them - you no longer can change them. If it is ok with you, or you documented what can and what can not be overriden - that's fine. Sometimes you just don't want it. Sometimes you just want to say - "just use this class, never inherit from it, because I want a freedom to change internal implementation details".
So basically comment "Because the class doesn't want to have any children and we should respect it's wishes" is correct.
So, someone wants to mark a class as final/sealed, when he thinks that possible implementation details changes are more valuable than inheritance. There are other ways to achieve results similar to inheritance.