接口的多重继承歧义
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 如何仍然避免钻石问题):
要遵循三个规则:
A class总是赢。 Class自己的方法实现优先于接口中的默认方法。
如果 class 没有:最具体的接口胜出
- 如果不是上述情况,继承 class 必须 明确说明 它正在使用哪个方法实现(否则无法编译)
具有虚拟声明的接口,它们不会有实现,因此没有
歧义问题。
我们都知道 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 如何仍然避免钻石问题):
要遵循三个规则:
A class总是赢。 Class自己的方法实现优先于接口中的默认方法。
如果 class 没有:最具体的接口胜出
- 如果不是上述情况,继承 class 必须 明确说明 它正在使用哪个方法实现(否则无法编译)
具有虚拟声明的接口,它们不会有实现,因此没有 歧义问题。