接口的多重继承歧义

Multiple Inheritance Ambiguity with Interface

我们都知道 diamond problem 关于多重继承 -

   A
  / \
 B   C
  \ / 
   D

此问题描述了 class D 的模棱两可的情况。如果 class A 有一个方法并且 B and/or C 的 both/either 覆盖了该方法那么哪个版本的方法执行 D覆盖?

这个问题是否也适用于 Java 中的接口?如果不是,Java 接口如何解决这个问题?

菱形问题仅适用于实现 继承(extends 在Java 8 之前的所有Java 版本中。它不适用于 API 继承(implements 在 Java 8 之前的所有 Java 版本中)。

由于具有匹配类型签名的接口方法是兼容的,因此如果您两次继承相同的方法签名就没有菱形问题:匹配的方法签名只是合并。 (如果类型签名不一样,那么你也不会有菱形问题。)

在 Java 7 及以下版本中,继承 实现 代码的唯一方法是通过 extends 关键字,该关键字最多限制为一个父级。因此不存在多重实现继承,不存在菱形问题

Java 8 增加了一个新问题,因为它允许接口具有实现代码。当您使用具有匹配签名的方法实现多个接口时,它仍然通过简单地回退到以前的行为(没有实现继承)来避免菱形问题。

Java不支持多重继承,所以不会出现菱形问题。如果 B & C 是接口,那么接口中没有实现。即使 B 和 C 覆盖了接口 A 中的方法(不能是 class),这些方法也将具有相同的签名。对于使用哪个实现没有歧义,因为没有实现。

Java 克服了这个问题,即使接口可以有方法的默认实现,因为默认实现是 unambiguous(class A) 或 某些规则 解决了这种情况(当 class B 或 class C 覆盖了来自class A,见下文)。

当 class 或接口的超类型提供多个具有相同签名的默认方法时:

  • 实例方法优先于接口默认方法。
  • 已被其他候选人覆盖的方法将被忽略。 当超类型共享一个共同的祖先时,就会出现这种情况

但是,如果两个或多个独立定义的默认方法冲突,或者默认方法与抽象方法冲突,则Java编译器会产生编译错误。您 必须显式覆盖超类型方法 。在这种情况下,您可以使用 super 关键字调用任何默认实现。

另请参阅:How does Java 8' new default interface model works (incl. diamond, multiple inheritance, and precedence)?

在Java8中引入的接口中的默认方法,可能会出现多重继承相关的问题,有3种情况 -

1- 如果实现 class 覆盖默认方法并为默认方法提供自己的功能,则 class 的方法优先于接口默认方法。

2-当 class 实现两个接口并且都具有相同的默认方法时,而且 class 没有覆盖该方法,那么将抛出错误。

3-如果一个接口扩展了另一个接口并且两者具有相同的默认方法,则继承接口的默认方法优先。

了解更多信息 here

添加关于 Java8 接口多重继承的现有答案(a.k.a。Java 如何仍然避免钻石问题):

要遵循三个规则:

  1. A class总是赢。 Class自己的方法实现优先于接口中的默认方法。

  2. 如果 class 没有:最具体的接口胜出

  1. 如果不是上述情况,继承 class 必须 明确说明 它正在使用哪个方法实现(否则无法编译)

具有虚拟声明的接口,它们不会有实现,因此没有 歧义问题。