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

Bim*_*thy 5 java interface multiple-inheritance

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

我不这么认为,例如:

// 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Ted*_*opp 12

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

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

类似的声明适用于接口(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
}
Run Code Online (Sandbox Code Playgroud)

编辑

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

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

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

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

  • 你能用代码展示你的意思吗?据我所知,变量不能从接口继承. (2认同)

Ósc*_*pez 11

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

public interface Foo {
    int x;
}
Run Code Online (Sandbox Code Playgroud)

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

public interface Foo {
    public static final int x;
}
Run Code Online (Sandbox Code Playgroud)

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

public interface Bar {
    int x;
}
Run Code Online (Sandbox Code Playgroud)

如果你要x在一个实现两者的类中使用该值Foo,Bar那么你必须对这些常量进行限定,不留任何歧义,如下所示:

public class Baz implements Foo, Bar {
    private int y = Foo.x + Bar.x;
}
Run Code Online (Sandbox Code Playgroud)

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


duf*_*ymo 5

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

如果您实际编写,编译和执行这些接口和类,您将得到答案.该x变量不是类成员,因此没有歧义.

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

  • 完全同意你的看法.但是因为我在这里问了这个问题,我得到了一些非常好的观点,比如使用import static,并在接口中使用枚举而不是常量(如其他用户所提到的).难道你不觉得我有额外的东西要学习吗?不,你认为这对我或其他人有帮助吗?我不想在这里浪费一些人的时间.如果有人觉得他们可以与我分享一些知识,他们应该......否则,完全无视我的问题.像我这样的人,编程的初学者需要像你这样的优秀程序员的帮助,先生.请鼓励我们问:) (2认同)

小智 3

Java 阻止多个具体/抽象类继承,但不阻止多个接口继承。通过多接口继承,您继承的是抽象方法,而不是实现。请参阅这篇文章,其中有很好的解释和示例:https://web.archive.org/web/20120724032720/http ://www.tech-knowledgy.com/interfaces-sovles-diamond-death/