在我写这个答案时,那篇维基百科文章当然需要一些爱。
鉴于您在 java 中进行了标记,具体来说:
- “钻石问题”用词不当;与所有条带的多重继承有关的问题很多,java只是避免了其中的一些;具有任何形式的多重继承的语言都不可能解决所有这些问题。
- 据推测,至少就 java 而言,diamond 的关键问题在于 java 在这方面与 C++ 的不同之处,因为在最初开发 java 时,大多数语言设计决策都是“我们只是做了 C(++) 所做的事情”,或者“我们决定偏离,因为 [C(++) 在这里所做的普遍接受的问题]”的味道。戴蒙德就是其中之一。具体来说:“与 C++ 不同,java 不允许扩展多个类,因为 [各种问题通常称为菱形问题]”。
- 这意味着,具体来说,ordering:如果您同时拥有
Parent1 和 Parent2 作为父类型(可能是因为假设的 extends Parent1, Parent2 或者是因为 extends Parent1 implements Parent2 或 @ 987654325@ - 最后两个在 java 中有效,Parent1 和 Parent2 都有相同的方法(例如,void method()),那么哪个实现“获胜”?
- Java 采用以下格言:顺序永远不重要。换句话说,如果 Parent1 和 Parent2 都提供相同方法的实现,那么在 C++ 中,第一个列出的类“获胜”。在 Java 中,您不能从 2 个类继承,所以这一点没有实际意义。您可以继承多个接口,但作为普通(即没有默认方法)接口不带来实现,这里没有任何问题:是的,如果您实现
Parent1 或 Parent2(本示例中的两个接口),您必须编写void foo() 的实现。如果你同时实现它们,你...必须为void foo() 编写一个实现。没问题。
因此,让我们继续将“钻石问题”定义为“避免订购问题”。此外,因为它是java,你仍然不能扩展不止一件事,所以我们实际上只是在谈论接口的顺序。如果您编写implements Parent1, Parent2,那么如果您编辑该源文件以读取implements Parent2, Parent1,是否有任何变化?在 C++ 中,答案是:“是的,这很重要”。在java中,答案应该是:“不,这是一个毫无意义的改变”。鉴于 java 中现在存在默认方法,让我们看看 java 是如何“解决”这个问题的:
extends Parent1 implements Parent2
给定:
class Parent1 {
public void foo() {
System.out.println("Parent1.foo");
}
}
interface Parent2 {
default void foo() {
System.out.println("Parent2.foo");
}
}
class Foo extends Parent1 implements Parent2 {}
然后这将编译,new Foo().foo(); 将打印Parent1.foo。这是因为在 java 中,类层次结构胜出:接口仅指定一个默认实现,如果没有其他 impl 可用,则使用该实现。还有一个可用的(来自Parent1),因此,它赢了。
您是否认为这是钻石问题的“解决方案”,取决于您如何定义“钻石问题”一词。没有一个统一的定义是普遍认可的。
implements Parent1, Parent2
给定:
interface Parent1 {
default void foo() {
System.out.println("Parent1.foo");
}
}
interface Parent2 {
default void foo() {
System.out.println("Parent2.foo");
}
}
class Foo implements Parent1, Parent2 {}
那么上面的无法编译。 Javac 检测到存在冲突(同一方法的 2 个相互竞争的实现),并且由于 顺序永远不重要,java 不能仅仅因为它被列在首位而给予这两种优先处理。
因此,javac 只会出错。您可以通过为该方法显式编写 impl 来修复它。您甚至可以选择一个(或两个!)父实现:
class Foo implements Parent1, Parent2 {
@Override public void foo() {
Parent1.super.foo();
Parent2.super.foo();
}
}
现在new Foo().foo() 将打印:
Parent1.foo
Parent2.foo
因此,即使 java 中的默认方法现在已经成为一件事(这正是“混入”的含义,所以即使该维基百科没有将 java 列为具有混入的语言,维基百科页面是错误的,事实上后面关于java的部分也是这么说的!) - 顺序仍然无关紧要。