java 接口能解决“致命的死亡钻石”问题吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9860811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Do interfaces solve the "deadly diamond of death" issue?
提问by Biman Tripathy
Do interfaces solve the deadly diamond of deathproblem?
接口能解决致命的死亡钻石问题吗?
I don't think so, for example:
我不这么认为,例如:
// 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);
}
}
Here we get an ambiguous x
.
在这里,我们得到了一个模棱两可的x
.
Though interfaces are a good way for solving method ambiguity, I guess they fail in the case of variables?
虽然接口是解决方法歧义的好方法,但我猜它们在变量的情况下会失败?
Am I correct? If I am missing something, enlighten me.
我对么?如果我遗漏了什么,请赐教。
采纳答案by Rizwan
Java prevents multiple concrete/abstract class inheritance, but not multiple interface inheritance. With multiple interface inheritance you inherit abstract methods, not implementation. See this post with a good explanation and examples: https://web.archive.org/web/20120724032720/http://www.tech-knowledgy.com/interfaces-sovles-diamond-death/
Java 防止多个具体/抽象类继承,但不防止多个接口继承。通过多接口继承,您继承的是抽象方法,而不是实现。看到这篇文章有很好的解释和例子:https: //web.archive.org/web/20120724032720/http: //www.tech-knowledgy.com/interfaces-sovles-diamond-death/
回答by Ted Hopp
When a class inherits two variables from parent interfaces, Java insists that any use of the variable name in question be fully qualified. This solves the problem. See the Java Language Specification Section 8.3:
当一个类从父接口继承两个变量时,Java 坚持任何对相关变量名的使用都是完全限定的。这解决了问题。请参阅Java 语言规范第 8.3 节:
It is possible for a class to inherit more than one field with the same name. Such a situation does not in itself cause a compile-time error. However, any attempt within the body of the class to refer to any such field by its simple name will result in a compile-time error, because such a reference is ambiguous.
一个类可以继承多个同名字段。这种情况本身不会导致编译时错误。但是,在类的主体内尝试通过简单名称引用任何此类字段将导致编译时错误,因为此类引用是不明确的。
A similar statement applies with respect to interfaces (JLS §9.3).
类似的声明适用于接口(JLS §9.3)。
The sample code in the answer by óscar Lópezis excellent. Here's another example:
óscar Ló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
}
Edit
编辑
Java 8 introduces a limited form of multiple inheritance for methods because interfaces now can declare default methodsthat subinterfaces and implementing classes can inherit. Since a class can implement multiple interfaces, this can cause ambiguities because distinct default methods with the same signature could be inherited from multiple interfaces.1Java deals with this using a priority scheme to specify which default method is actually inherited. It requires explicitly overriding inherited default methods when the priority scheme fails to yield a single winner.
Java 8 为方法引入了一种有限形式的多重继承,因为接口现在可以声明子接口和实现类可以继承的默认方法。由于一个类可以实现多个接口,这可能会导致歧义,因为可以从多个接口继承具有相同签名的不同默认方法。1Java 使用优先级方案来处理这个问题,以指定实际继承哪个默认方法。当优先级方案未能产生单个获胜者时,它需要显式覆盖继承的默认方法。
Note that in no case does Java have a Diamond problem, which is a very specific subclass of problems that can come with multiple inheritance.2The "Diamond" part refers to the shape of the class inheritance diagram that's required in order to have the problem. In C++, the Diamond problem can arise if a class A inherits from two classes B and C, each of which inherits from a common base class D. In that case, any public members of D ends up appearing twice in A—once inherited through B and once through C. Also, whenever an instance of A is constructed or destroyed, the constructor or destructor for D ends up being called twice (often with disastrous consequences, hence the "of death" part of the name). C++ solves these issues by providing virtual inheritance. (See the discussion herefor details.)
请注意,Java 在任何情况下都没有钻石问题,这是一个非常具体的问题子类,可以伴随多重继承而来。2“菱形”部分指的是出现问题所需的类继承图的形状。在 C++ 中,如果类 A 继承自两个类 B 和 C,每个类都继承自一个公共基类 D,则会出现钻石问题。在这种情况下,D 的任何公共成员最终都会在 A 中出现两次——一次通过继承B 和一次通过 C。此外,每当 A 的实例被构造或销毁时,D 的构造函数或析构函数最终都会被调用两次(通常会带来灾难性的后果,因此名称的“死亡”部分)。C++ 通过提供虚拟继承解决了这些问题。详情请看这里。)
1 Note the use of the word "distinct". There is no issue if the samedefault method is inherited through two parent interfaces that in turn extend a common base interface where the default method is defined; the default method is simply inherited.
1 请注意“不同”一词的使用。如果通过两个父接口继承相同的默认方法,则没有问题,这两个父接口又扩展了定义默认方法的公共基接口;默认方法只是继承。
2 Other multiple inheritance issues—like the ambiguities that can arise in Java with interface fields, static methods, and default methods—technically have nothing to do with the Diamond problem (actually, the Deadly Diamond of Death problem). However, much of the literature on the subject (and an earlier version of this answer) ends up lumping all multiple inheritance problems under the rubric "Diamond of Death." I guess the name is just too cool to be used only when technically appropriate.
2 其他多重继承问题——比如在 Java 中可能出现的带有接口字段、静态方法和默认方法的歧义——从技术上讲,与钻石问题(实际上,死亡钻石问题)无关。然而,关于这个主题的大部分文献(以及这个答案的早期版本)最终都将所有多重继承问题归为“死亡钻石”的标题。我想这个名字太酷了,不能只在技术上合适的时候使用。
回答by óscar López
An interface can't have attributes. When you write this:
接口不能有属性。当你写这个时:
public interface Foo {
int x;
}
Under the hood it implicitly gets converted to a constant, something like this:
在引擎盖下,它隐式地转换为常量,如下所示:
public interface Foo {
public static final int x;
}
Let's say you have another interface with a similarly named constant:
假设您有另一个具有类似命名常量的接口:
public interface Bar {
int x;
}
And if you were to use the x
value in a class that implements both Foo
and Bar
you'll have to qualify those constants, leaving no room for ambiguities, like this:
如果你使用x
值一类同时实现了Foo
和Bar
你有资格这些常量,不留下任何余地含糊,就像这样:
public class Baz implements Foo, Bar {
private int y = Foo.x + Bar.x;
}
So no diamond in here. Anyway, declaring constants in an interface is frowned upon nowadays, most of the time you're better off using an enumeration for the same effect.
所以这里没有钻石。无论如何,现在不赞成在接口中声明常量,大多数情况下最好使用枚举来实现相同的效果。
回答by duffymo
No, you don't. Interfaces don't have any variables, other than static final ones.
不,你没有。接口没有任何变量,除了静态最终变量。
If you actually write, compile, and execute those interfaces and classes you'll have your answer. That x
variable is not a class member, so there's no ambiguity.
如果您实际编写、编译和执行这些接口和类,您就会得到答案。该x
变量不是类成员,因此没有歧义。
This is one of those questions that you can easily answer for yourself by writing the code and letting the JDK tell you. It'll be faster than asking here.
这是您可以通过编写代码并让 JDK 告诉您自己轻松回答的问题之一。这比在这里问要快。
回答by Nirbhay Mishra
Deadly Diamond Of Death Problem.
致命的死亡钻石问题。
class A
{
void eat()
{
print("I am eating Apple")
}
}
class B and C extend A and Override eat() method
B 类和 C 类扩展 A 并覆盖eat() 方法
class B extends A
{
void eat()
{
print("I am eating Banana")
}
}
class C extends A
{
void eat()
{
print("I am eating Grapes")
}
}
Now if java had multiple Inheritance ? what will Happen in the following case.
现在,如果 java 有多个继承?在以下情况下会发生什么。
class D extends B ,C
{
//which eat() method will be inherited here for class D ? a problem ? ?
}
回答by supercat
The Deadly Diamond of Death is a problem with variables, but an even bigger problem with virtual methods. If classes Moo1
and Moo2
were to both inherit from class Foo
and override abstract virtual function Bar
, and if a class Zoo
were allowed to inherit from Moo1
and Moo2
, without having to add its own override of Bar
, it it would be unclear what method Bar
of a Zoo
should do. Interfaces avoid that issue by requiring that every class that implements an interface must supply its own implementation for all of the interface members, and by specifying that all members of an interface will be considered identical in all interfaces which extend it directly or indirectly. Thus, in the above situation, if Foo
, etc. were interfaces rather than classes, then any class which implements Zoo
would be required to implement Foo.Bar
, which would be synonymous with Moo1.Bar
, Moo2.Bar
, and Zoo.Bar
.
致命的死亡钻石是变量的问题,但虚拟方法的问题更大。如果类Moo1
和Moo2
都继承自类Foo
并覆盖抽象虚函数Bar
,并且如果Zoo
允许类继承自Moo1
and Moo2
,而不必添加自己的覆盖Bar
,则不清楚Bar
a 的方法Zoo
应该做什么。接口通过要求实现接口的每个类都必须为所有接口成员提供自己的实现来避免这个问题,并通过指定接口的所有成员在直接或间接扩展它的所有接口中都将被视为相同。因此,在上述情况下,如果Foo
等是接口而不是类,然后实现所有类Zoo
将需要实现Foo.Bar
,这将是同义的Moo1.Bar
,Moo2.Bar
和Zoo.Bar
。