这是非常经典的问题,与“为什么 String 类在 Java 中是不可变的”很类似; 这两个问题之间的相似之处在于它们主要是由 Java 创作者的设计决策使然。

Java 不支持类的多继承。因为多继承会增加编程的复杂性。下图选自孙卫琴的经典Java书籍《漫画Java编程》

Java面试题支招-为什么Java语言不支持多继承_构造方法

当一个子类有多个父类可能出现的混乱

为什么Java不支持多重继承, 可以考虑以下几点:

1、第一个原因是围绕钻石问题产生的歧义,考虑一个类 A 有 foo() 方法, 然后 B 和 C 派生自 A, 并且有自己的 foo() 实现,现在 D 类使用多个继承派生自 B 和C,如果我们只引用 foo(), 编译器将无法决定它应该调用哪个 foo()。这也称为 Diamond 问题,因为这个继承方案的结构类似于菱形,见下图:

Java面试题支招-为什么Java语言不支持多继承_Java_02

即使我们删除钻石的顶部 A 类并允许多重继承,我们也将看到这个问题含糊性的一面。如果你把这个理由告诉面试官,他会问为什么 C++ 可以支持多重继承而 Java不行。嗯,在这种情况下,我会试着向他解释我下面给出的第二个原因,它不是因为技术难度, 而是使得程序代码具有更好的可维护和更清晰的设计, 虽然这只能由 Java 言语设计师确认,我们只是推测。

2、第二个也是更有说服力的理由是,多重继承确实使设计变得复杂化。例如在创建子类对象时,会先调用父类的构造方法,再调用子类的构造方法,参见:探秘子类调用父类的构造方法的方式

在多继承情况下,构造方法的调用顺序会变得很复杂。假设你需要多重继承的情况并不多,简单起见,明智的决定是省略它。

3、如果一个类A已经继承了类B,类A还需要继承类C,该怎么办呢?Java提倡用组合来替代继承。在类A中包装一个类C的实例,就能访问类C的功能了。示范代码如下:

public A extends B{
  C c;  // 类A中包装类C的实例

  public A(C c){this.c=c;}

  public void test(){
    c.doSome();  // 使用类C的功能
  }
}

上文参考孙卫琴的经典Java书籍。

Java面试题支招-为什么Java语言不支持多继承_构造方法_03