Java 8 Java8没有';t提供相同的解决方案来允许多重继承,这与他们提供的解决接口默认方法相同

Java 8 Java8没有';t提供相同的解决方案来允许多重继承,这与他们提供的解决接口默认方法相同,java-8,multiple-inheritance,default-method,Java 8,Multiple Inheritance,Default Method,问题: 我们知道Java不允许扩展多个类,因为这会导致编译器无法决定使用哪个超类方法。使用接口默认方法,钻石问题是在Java8中引入的。也就是说,如果一个类实现了两个接口,每个接口定义了相同的默认方法,并且实现类没有覆盖公共的默认方法,那么编译器就无法决定选择哪个实现 解决方案: Java8需要为由多个接口实现的默认方法提供实现。因此,如果一个类将实现上面提到的两个接口,那么它必须为公共默认方法提供一个实现。否则编译器将抛出编译时错误 问题: 为什么这个解决方案不适用于多类继承,因为它覆盖了子类

问题:

我们知道Java不允许扩展多个类,因为这会导致编译器无法决定使用哪个超类方法。使用接口默认方法,钻石问题是在Java8中引入的。也就是说,如果一个类实现了两个接口,每个接口定义了相同的默认方法,并且实现类没有覆盖公共的默认方法,那么编译器就无法决定选择哪个实现

解决方案:

Java8需要为由多个接口实现的默认方法提供实现。因此,如果一个类将实现上面提到的两个接口,那么它必须为公共默认方法提供一个实现。否则编译器将抛出编译时错误

问题:


为什么这个解决方案不适用于多类继承,因为它覆盖了子类引入的常用方法?

接口引入的方法可能总是被覆盖,而类引入的方法可能是最终的。这就是为什么您可能无法对类应用与接口相同的策略的原因之一。

您没有正确理解菱形问题(当然,维基百科文章的当前状态没有充分解释它)。如图所示

当同一个类通过不同的继承路径被多次继承时,就会出现菱形问题。这对于接口来说不是问题(从来都不是),因为它们只定义一个契约,多次指定同一个契约没有什么区别

主要问题不是与方法相关,而是与超类型的数据相关。在这种情况下,
A
的实例状态应该存在一次还是两次?如果有一次,
C
B
可以对
A
的实例状态具有不同的、冲突的约束。这两个类也可能假设对<代码> A<代码>状态进行完全控制,即不考虑其他类具有相同的访问级别。如果有两个不同的
A
状态,则
D
引用到
A
引用的扩展转换变得不明确,因为
A
可能意味着其中一个

接口没有这些问题,因为它们根本不携带实例数据。他们也(几乎)没有可访问性问题,因为他们的方法总是
公共的
。允许
default
方法不会改变这一点,因为
default
方法仍然不访问实例变量,而只使用接口方法进行操作

当然,有可能
B
C
声明了具有相同签名的
default
方法,导致必须在
D
中解决的歧义。但如果没有
A
,即根本没有“钻石”,情况就更是如此。因此,这个场景不是“钻石问题”的正确例子。

描述为“钻石问题”的冲突可以通过对方法
a.m()的多态调用来最好地说明
其中接收器的运行时类型为
D
:想象
D
继承了两种不同的方法,它们都声称扮演
A.m()
的角色(其中一种可能是原始方法
A.m()
,至少其中一种是覆盖)。现在,动态分派无法决定调用哪个冲突方法

旁白:“钻石问题”和常规名称冲突之间的区别在埃菲尔等语言中尤其重要,在这些语言中,冲突可以从类型
D
的角度局部解决,例如,通过重命名一种方法。这将避免静态类型为
D
的调用的名称冲突,但不会避免静态类型为
A
的调用的名称冲突

现在,使用Java 8中的默认方法,JLS被修改为检测任何此类冲突的规则,需要
D
来解决冲突(存在许多不同的情况,取决于所涉及的某些类型是否为类)。也就是说,钻石问题在Java8中并没有“解决”,只是通过拒绝任何可能产生钻石的程序来避免钻石问题

理论上,Java1中可以定义类似的规则来允许类的多重继承。这只是早期的一个决定,Java的设计者不想支持多重继承


对于默认方法而不是类方法,允许多重(实现)继承的选择纯粹是一种务实的选择,不是任何理论所必需的。

我同意菱形问题的共享状态论点,但不是更少,如果您想在Java中支持多重继承,那么您必须处理选择单个方法的多个实现之一的问题。这个问题在问题和如何解决Java8中的接口中进行了说明。同样的解决方案不能保证应用于类。还是我遗漏了什么?@Harmlez:正如上一段所述,必须在多个继承的非抽象方法之间消除歧义的问题通常是一个多重继承的问题,但它不需要出现一个普通的超类型,因此,与菱形问题无关。您是对的,对于非
接口类
类来说,这是一个无法用同样的方法解决的问题,但它仍然不是称为“菱形问题”的特定问题。