最终和密封的目的

Cha*_*adD 9 oop final sealed

为什么有人想要将课程标记为最终或密封?

Mar*_*off 14

根据维基百科的说法,"密封类主要用于防止派生.它们在编译时增加了另一级严格性,提高了内存使用率,并触发了一些可以提高运行时效率的优化."

另外,来自Patrick Smacchia的博客:

  • 版本控制:当一个类最初被密封时,它可以在将来更改为未密封而不会破坏兼容性.(......)

  • 性能:(...)如果JIT编译器看到使用密封类型调用虚方法,JIT编译器可以通过非虚拟地调用该方法来生成更高效的代码.(...)

  • 安全性和可预测性:一个类必须保护自己的状态,不允许自己被破坏.当一个类被解封时,如果内部操作字段的任何数据字段或方法是可访问的而不是私有的,派生类可以访问和操作基类的状态.(...)

这些都是很好的理由 - 在我刚才查看之前,我实际上并没有意识到性能优势的影响:)

版本控制和安全点在代码置信度方面似乎是一个巨大的好处,这在任何类型的大型项目中都是非常合理的.当然,它不是用于单元测试的插件,但它会有所帮助.

  • 版本控制?我不遵循这个.这听起来像你的说法"你可以从课堂上删除'密封'属性并重新编译" - 这并不能说明你为什么要这样做.性能?有趣!安全?子类只能访问基类允许的内容.如果基类希望"保护"其数据,则不应使用"受保护"属性.这不是密封整个班级的理由.我想念它. (2认同)

And*_*are 10

因为创建一个继承类型比大多数人想象的要困难得多.默认情况下,最好以这种方式标记所有类型,因为这将阻止其他类型继承自从未打算扩展的类型.

是否应该扩展类型是创建它的开发人员的决定,而不是稍后出现并希望扩展它的开发人员.

  • 我在这方面做了下注,但不要认为它是-1情况:)使用限制性密封的第三方代码可能会让生活变得悲惨,特别是当需要解决bug时.不止一次,我不得不包装错误的类,因为保护级别是不必要的限制. (3认同)

Pav*_*man 6

Joshua Bloch在他的着作Effective Java中谈到了它.他说"继承或禁止它的文件".关键是类是作者和客户之间的契约.允许客户端从基类继承使得此合同更加严格.如果你要继承它,你很可能会覆盖一些方法,否则你可以用组合替换继承.允许覆盖哪些方法,以及实现它们必须执行的操作 - 应该记录,否则您的代码可能会导致不可预测的结果.据我所知,他展示了这样的例子 - 这是一个带方法的集合类

public interface Collection<E> extends Iterable<E> {    
  ...
  boolean add(E e);
  boolean addAll(Collection<? extends E> c);
  ...
}
Run Code Online (Sandbox Code Playgroud)

有一些实现,即ArrayList.现在您希望从它继承并覆盖某些方法,因此它会在添加元素时打印以控制消息.现在,你需要覆盖addaddAll,还是只添加?这取决于addAll的实现方式 - 它是直接使用内部状态(如ArrayList所做)还是调用add(如AbstractCollection那样).或者可能有addInternal,addaddAll都会调用addInternal.在你决定继承这门课之前,没有这样的问题.如果你只是使用它 - 它不会打扰你.因此,如果他希望你继承他的班级,那么该班的作者必须记录它.

如果他想在未来改变实施怎么办?如果只使用他的类,从不继承,那么没有什么能阻止他将实现更改为更高效.现在,如果你从该类继承,查看源代码并发现addAll调用add,则只覆盖add.后来作者更改了实现,因此addAll不再调用add - 您的程序已损坏,调用addAll时不会打印消息.或者您查看了源代码,发现addAll不会调用add,因此您可以覆盖addaddAll.现在作者改变了实现,所以addAll调用add - 你的程序再次被破坏,当调用addAll时,每个元素都会打印两次消息.

所以 - 如果你想继承你的类,你需要记录如何.如果您认为将来可能需要更改可能会破坏某些子类的内容 - 您需要考虑如何避免它.通过让您的客户从您的类继承,您可以公开更多内部实现细节,当您让他们使用您的类时,您会公开内部工作流程,这通常会在未来版本中发生变化.

如果您公开了一些细节而客户依赖它们 - 您将无法再更改它们.如果你没事,或者你记录了什么可以和什么不能被覆盖 - 那没关系.有时你只是不想要它.有时你只想说 - "只是使用这个类,永远不要继承它,因为我想要自由地改变内部实现细节".

所以基本上评论"因为班级不想要任何孩子,我们应该尊重它的愿望"是正确的.

因此,有人想将一个类标记为最终/密封,当他认为可能的实现细节更改比继承更有价值时.还有其他方法可以实现类似于继承的结果.