不支持多重继承主要是因为会产生“菱形继承”,也称为钻石继承的问题。
那什么是菱形继承呢?
它涉及到一个类继承两个父类,而这两个父类又继承自同一个祖先类。这种结构在没有适当处理的情况下,会导致继承层次中的歧义和冗余。
如图所示:
假设有四个类:A、B、C、D。类B和类C都继承自类A,然后类D继承自类B和类C。这种结构看起来像一个菱形,因此得名。
菱形继承的问题在于,如果类A中有一个属性或方法,类B和类C都继承了这个属性或方法,那么类D将从B和C继承两次相同的属性或方法,这会导致数据冗余和潜在的歧义。
那既然多继承不行,那为什么接口多实现可以?
在Java8之前,对于接口,是无法定义具体方法实现的,所以即使有多个接口,必须子类自己去实现,所以并不会发生歧义。
那么在Java8之后呢,就出了默认方法,但新问题出现了,此时不就又出现了多继承的菱形继承问题了吗?
所以Java强制规定,如何多个接口内有相同的默认方法,子类必须重写这个方法。
补充:默认方法具有以下特点
- 使用
default
关键字声明。- 可以有方法体,提供具体实现。
- 实现接口的类会自动继承默认方法,除非被覆盖。
否则,编译器就会出现如下报错:
解决办法则为上述中提到的重写该方法:
示例代码:
interface A {
default void say() { System.out.println("Hello from A"); }
}
interface B {
default void say() { System.out.println("Hello from B"); }
}
class C implements A, B {
@Override
public void say() {
A.super.say(); // 或者 B.super.say();
}
}
解决多继承问题的规则
Java 8规定了一套规则来解决接口默认方法的多继承问题:
- 类方法优先:如果实现类提供了方法的实现,那么这个实现会覆盖所有接口中的默认方法。
- 子接口优先:如果实现类没有提供方法的实现,那么会选择更具体的接口中的默认方法。如果一个接口继承了另一个接口,那么子接口的默认方法会被优先选择。
- 显式覆盖:如果上述规则都无法解决冲突,那么实现类必须显式地覆盖这个方法,并指定使用哪个接口的默认方法。