为什么OOP中有一个选项可以将类标记为从不从祖先继承?
C#中的“sealed”关键字,Java中的Final 由于我几乎从不创建任何图表,我只使用已经完成的类(来自框架),多年后我仍然不知道为什么会有人“锁定”一个类,这样它就永远不会被扩展/继承 它有用吗? 所有的类都有可能从继承扩展到抛弃“封印”的可能性,这有什么害处吗 很抱歉在2012年问这个问题,OOP在哪里是微不足道的,但我想得到一个好的解释和/或一个好的阅读来源!因为对我来说是无用的,我不能相信这只是一个简单的概念 但无论我在哪里搜索,答案都是一样的:“标记一个类,防止它从其他类继承。”为什么OOP中有一个选项可以将类标记为从不从祖先继承?,oop,inheritance,Oop,Inheritance,C#中的“sealed”关键字,Java中的Final 由于我几乎从不创建任何图表,我只使用已经完成的类(来自框架),多年后我仍然不知道为什么会有人“锁定”一个类,这样它就永远不会被扩展/继承 它有用吗? 所有的类都有可能从继承扩展到抛弃“封印”的可能性,这有什么害处吗 很抱歉在2012年问这个问题,OOP在哪里是微不足道的,但我想得到一个好的解释和/或一个好的阅读来源!因为对我来说是无用的,我不能相信这只是一个简单的概念 但无论我在哪里搜索,答案都是一样的:“标记一个类,防止它从其他类继承。”
equals()
这样的方法更简单,而不必考虑继承原因是,如果您允许子类化,并且不对子类可以重写的方法设置任何限制,那么对保留其行为的基类的更新仍然会破坏子类。换句话说,从一个不是专门设计用来扩展的类继承是不安全的(通过将特定方法指定为可重写的,并使所有其他的
final
),这就是所谓的脆弱基类问题——请参见示例,以获取对该问题的更全面的分析
如果基类不是为继承而设计的,并且它是公共API(可能是库)的一部分,那么现在您就有严重的麻烦了。您无法控制谁在子类化您的代码,您也无法仅通过查看基类就知道更改对子类是否安全底线是您要么设计为无限继承,要么完全不允许继承。
请注意,可能有有限数量的子类。这可以通过私有构造函数和内部类实现:
class Base {
private Base() {}
(public|private) static final class SubA extends Base { ... }
(public|private) static final class SubB extends Base { ... }
(public|private) static final class SubC extends Base { ... }
}
内部类可以访问私有构造函数,但顶级类不能,因此只能从内部对其进行子类化。这允许您表达“Base类型的值可以是SubA或SubB或SubC”的概念。这里没有危险,因为Base通常是空的(您并没有真正从Base继承任何内容),并且所有子类都在您的控制之下
您可能认为这是一种代码味道,因为您知道子类的类型。但是您应该认识到,这种实现抽象的替代方法是对接口的补充。当子类数量有限时,很容易添加新函数(处理固定数量的子类),但很难添加新类型(每个现有方法都需要更新以处理新的子类)。当您使用接口或允许无限子类化时,添加新类型(实现固定数量的方法)很容易,但添加新方法很难(您需要更新每个类)。一个人的长处就是另一个人的短处。有关此主题的更详细讨论,请参阅编辑:我的错误;我链接的论文讨论了不同的二元性(ADT与对象/接口)。我实际上想到的是
还有一些不太严重的原因可以避免继承。假设您从类A开始,然后在子类B中实现一些新特性,然后在子类C中添加另一个特性。然后您意识到您需要这两个特性,但您不能创建一个同时扩展B和C的子类BC。即使您为继承而设计并防止脆弱的基类问题,也有可能因此而受到影响。除了上面显示的模式,例如,使用(或者如果您的语言支持的话,简单地使用高阶函数。)Prime-example,为什么有人想从这个类继承
class-ConsoleApplication12345{public-static-void-main(){Console.Writeline(“Hello-World”);}
,说实话,我从未试图继承主类!我来看看。汉克斯,我不知道这五件事。有道理。我想了解更多关于OOP的细节。