我正在阅读J. Bloch的 Effective Java ,现在我正在继承与组合部分。据我所知,他说继承并不总是好的。
子类中脆弱性的一个相关原因是它们的超类 可以在后续版本中获取新方法。假设一个程序 取决于其所有元素插入的事实的安全性 一些集合满足一些谓词。这可以通过来保证 继承集合并覆盖每个能够的方法 添加元素以确保在之前满足谓词 添加元素。这可以正常工作,直到新方法能够 插入元素会在后续版本中添加到超类 释放。
但为什么它不起作用?超类只是Collection
接口,如果我们添加一个新方法,我们只是一个编译时错误。这有点无益......
答案 0 :(得分:19)
假设某些库v1.0中有一个Collection超类:
public class LimitedLengthCollection extends MyCollection {
@Override
public void add(String s) {
if (s.length() == 5) {
super.add(s);
}
}
}
您将其子类化,以便只接受长度为5的字符串
public class MyCollection {
public void add(String s) {
// add to inner array
}
public void addMany(String[] s) {
// iterate on each element and add it to inner array
}
}
合同,这个类的不变量是它永远不会包含长度为5的字符串。
现在发布了该库的2.0版本,并开始使用它。基类修改为:
LimitedLengthCollection c = new LimitedLengthCollection();
c.addMany(new String[] {"a", "b", "c"});
并且您的子类未经修改。现在你的子类的用户可以做
{{1}}
因此破坏了子类的合同。它应该只接受长度为5的字符串,而且它不再存在,因为在超类中添加了一个额外的方法。
答案 1 :(得分:3)
问题不在于继承不起作用。
问题在于,对于继承,开发人员无法强制执行某些行为(例如满足某些谓词的集合示例)。
当我们很少创建一个新类时,它确实是另一个类的专用类型。更常见的是使用其他类的新东西。
我们很少需要继承,更常见的是我们需要创建一个使用其他类的类来实现这一点。
IS A vs HAS A
你必须问自己:
B类是A类的新子类型,它以不同的方式处理A的相同事物?
或
B类HAS里面的一个类做一些不同的东西 A打算做什么?
并且知道更经常正确回答后者。
答案 2 :(得分:2)
因为它(通常)会破坏已实现Collection类的客户端代码。
在此特定示例中,安全性将被破坏,因为恶意用户可以使用在您发送代码后添加的非覆盖方法来插入项目。
将您的代码基于继承您无法控制的类可能会在将来咬你。
答案 3 :(得分:2)
如果我们添加一个新的mehtod,我们只是一个编译时错误
仅当将抽象方法添加到超类/接口时才是这样。如果添加了非抽象方法,则完全有效,不要覆盖该新方法。