java中继承的缺点

时间:2010-06-30 14:59:05

标签: java inheritance

任何人都可以解释java中继承的缺点

5 个答案:

答案 0 :(得分:9)

你可能想读:

Effective Java™,第二版 作者:Joshua Bloch

第4章类和接口

第16项:赞成合成而不是继承

第17项:继承的设计和文件,否则禁止它

第18项:首选接口到抽象类

答案 1 :(得分:5)

看看Allen Holub在JavaWorld上发表的题为Why extends is evil的文章。他讨论了紧耦合问题和fragile base class问题。

答案 2 :(得分:3)

除非你的课程是为继承而设计的,否则它应该是最终的。您必须非常小心,以确保您了解将在子类中重写的方法,这些方法不是为继承函数设计的,以便了解如何修改它们。

具体示例:

考虑你有一个管理名单列表的类......

public class MyNameManager {
  private List<String> numbers = new LinkedList<String>();

  public void add(String value) {
    numbers.add(value);
  }

  public void addAll(Collection<String> values) {
    for(String value : values) {
      add(value);
    }
  }

  public void remove(String value) { //... }

  //...
}

现在说你要创建一个新的子类,它也计算一个名称被添加到列表的总次数,如下所示:

public class MyCountingNameManager extends MyNameManager {
  private int count = 0;

  @Override
  protected void addAll(Collection<String> values) {
    count += values.size();
    super.addAll(values);
  }

  @Override
  protected void add(String value) {
    count += 1;
    super.add(value);
  }
}

看起来很简单,不是吗?但请考虑以下结果:

MyCountingNameManager m = new MyCountingNameManager();
m.add("bob");
m.add("Sally");

计数现在是2,一切都很顺利。但是如果我们要做以下事情:

List<String> family = new List<String>();
family.add("mom");
family.add("dad");
family.add("brother");

MyCountingNameManager m = new MyCountingNameManager();
m.add(family);

现在计数为6,您可能期望的3。这是因为对addAll的调用会将值集合(大小为3)的大小添加到计数中,然后调用super.addAll方法进行实际处理。 super.addAll迭代Collection并为每个值调用add方法。但由于我们使用MyCountingNameManager而非 a MyNameManager,因此每次调用子类中重写的add方法。执行的MyCountingNameManager.add方法也会增加计数!结果是每个名字都被计算两次!

我相信这个例子来自Effective Java。你肯定应该找到一份副本并阅读Viele答案中列出的项目,以便更深入地了解继承不合适的一些情况。

答案 3 :(得分:2)

我们更喜欢组合而不是继承,因为当我们通过子类添加(特别)或更改功能时,我们将新功能耦合到类中 - 因此,只要我们需要新功能,我们就需要该类。这甚至扩展到了更多的子类 - 并且使用Java的单继承模型,如果我们在另一个类中有两个新的功能位,那么没有(简单)方法将两个位都带入,如果每个位都在一个单独的子类中原始的祖先。

相比之下,如果我们通过组合扩展功能,任何类 - 在我们现有的层次结构内外 - 都可以通过简单地包含具有新功能的小类来合并它。它更简单,更清洁,更可重复使用,更易于阅读。

继承有其地位,但它不是许多工作的正确工具。

答案 4 :(得分:0)

继承提供了类之间的紧密耦合关系,与运行时多态性的接口相比,它具有沉重的负担。