界面是否解决了“致命的死亡钻石”问题?

界面是否解决了死亡问题的致命钻石

我不这么认为,例如:

// A class implementing two interfaces Interface1 and Interface2. // Interface1 has int x=10 and Interface2 has int x = 20 public class MultipleInterface implements Interface1, Interface2{ public void getX(){ System.out.println(x); } } 

在这里我们得到一个模棱两可的x

虽然接口是解决方法模糊性的好方法,但我猜它们在变量的情况下会失败?

我对么? 如果我遗失了什么,请赐教。

Java可以抵抗多个Concrete / abstract类inheritance,但不能inheritance多个接口inheritance,在这种情况下,inheritance抽象方法并不能实现更好的post,并且具有良好的解释和示例http://www.tech-knowledgy.com/interfaces-sovles-diamond-death/

当一个类从父接口inheritance两个变量时,Java坚持认为对所讨论的变量名的任何使用都是完全限定的。 这解决了这个问题。 请参阅Java语言规范第8.3节 :

类可以inheritance多个具有相同名称的字段。 这种情况本身并不会导致编译时错误。 但是,在类的主体内通过其简单名称引用任何此类字段的任何尝试都将导致编译时错误,因为这样的引用是不明确的。

类似的陈述适用于接口( JLS§9.3 )。

ÓscarLópez的答案中的示例代码非常出色。 这是另一个例子:

 class Base { int x = 10; } interface Interface { int x = 20; } class SingleInheritance implements Interface { int y = 2 * x; // ok } class MultipleInheritance extends Base implements Interface { int y = 2 * x; // compile-time error int z = 2 * Interface.x; // ok } void aMethod(MultipleInheritance arg) { System.out.println("arg.x = " + arg.x); // compile-time error System.out.println("x = " + Interface.x); // ok } 

编辑

Java 8为方法引入了一种有限forms的多重inheritance,因为接口现在可以声明子接口和实现类可以inheritance的默认方法 。 由于类可以实现多个接口,因此可能会导致歧义,因为具有相同签名的不同默认方法可以从多个接口inheritance。 1 Java使用优先级方案处理此事务,以指定实际inheritance的默认方法。 当优先级方案无法产生单个赢家时,它需要显式重写inheritance的默认方法。

请注意,在任何情况下,Java都不会出现Diamond问题,这是一个非常具体的问题子类,可能带有多重inheritance。 2 “钻石”部分指的是为了解决问题所需的类inheritance图的形状。 在C ++中,如果类Ainheritance自两个类B和C,则会出现Diamond问题,每个类inheritance自公共基类D.在这种情况下,D的任何公共成员最终在A中出现两次,一次inheritanceB和一次通过C.此外,每当A的实例被构造或销毁时,D的构造函数或析构函数最终被调用两次(通常带有灾难性的后果,因此名称中的“死亡”部分)。 C ++通过提供虚拟inheritance来解决这些问题。 (有关详细信息,请参阅此处的讨论。)

1 注意使用“distinct”一词。 如果通过两个父接口inheritance相同的默认方法则没有问题,这两个父接口又扩展了定义默认方法的公共基接口; 默认方法只是inheritance。

2 其他多重inheritance问题 – 比如Java中可能出现的带有接口字段,静态方法和默认方法的歧义 – 技术上与Diamond问题(实际上是Deadly Diamond of Death问题)无关。 然而,关于这个主题的大部分文献(以及这个答案的早期版本)最终都将所有多重inheritance问题归结为“死亡之钻”。 我想这个名字太酷了,只有在技术上合适时才能使用。

接口不能具有属性。 当你写这个:

 public interface Foo { int x; } 

它隐藏地转换为常量,如下所示:

 public interface Foo { public static final int x; } 

假设您有另一个具有类似命名常量的接口:

 public interface Bar { int x; } 

如果你在实现FooBar的类中使用x值,你将必须限定这些常量,不留任何歧义,如下所示:

 public class Baz implements Foo, Bar { private int y = Foo.x + Bar.x; } 

所以这里没有钻石。 无论如何,在界面中声明常量是不受欢迎的,现在大多数时候你最好使用枚举来获得相同的效果。

不,你没有。 除了静态的最终变量之外,接口没有任何变量。

如果您实际编写,编译和执行这些接口和类,您将得到答案。 那个x变量不是类成员,所以没有歧义。

这是您可以通过编写代码并让JDK告诉您自己轻松回答的问题之一。 它会比在这里问更快。

致命的死亡钻石问题。

 class A { void eat() { } } 

B和C类扩展了A和Override eat()方法

 class B extends A { void eat() { } } class C extends A { void eat() { } } 

现在,如果我们有多个inheritance,在下面的情况下会发生什么。

  class D extends B ,C { //which eat() method will be inherited here for class D ? a problem ? ? } 

死亡的死亡钻石是变量的问题,但虚拟方法的问题更大。 如果类Moo1Moo2都从类Fooinheritance并覆盖抽象虚函数Bar ,并且如果允许类ZooMoo1Moo2inheritance,而不必添加自己的Bar重写,那么它将不清楚是什么方法Zoo Bar应该做。 接口通过要求实现接口的每个类必须为所有接口成员提供其自己的实现,并通过指定接口的所有成员在所有直接或间接扩展它的接口中被视为相同来避免该问题。 因此,在上面的情况下,如果Foo等是接口而不是类,那么实现Zoo任何类都需要实现Foo.Bar ,它将与Moo1.BarMoo2.BarZoo.Bar