Answers:
如果一个类型实现两个接口,并且每个接口interface
定义一个具有相同签名的方法,则实际上只有一个方法,并且它们是不可区分的。如果说这两个方法的返回类型冲突,那么将是编译错误。这是继承,方法覆盖,隐藏和声明的一般规则,并且不仅适用于两个继承的interface
方法之间的可能冲突,还适用于an interface
和super class
方法之间的冲突,甚至仅适用于泛型类型擦除引起的冲突。
在下面的示例中,您有一个interface Gift
具有present()
方法(例如,赠送礼物)的和interface Guest
,还具有一种present()
方法(例如,客人在场并且不在场)。
Presentable johnny
都是 Gift
和Guest
。
public class InterfaceTest {
interface Gift { void present(); }
interface Guest { void present(); }
interface Presentable extends Gift, Guest { }
public static void main(String[] args) {
Presentable johnny = new Presentable() {
@Override public void present() {
System.out.println("Heeeereee's Johnny!!!");
}
};
johnny.present(); // "Heeeereee's Johnny!!!"
((Gift) johnny).present(); // "Heeeereee's Johnny!!!"
((Guest) johnny).present(); // "Heeeereee's Johnny!!!"
Gift johnnyAsGift = (Gift) johnny;
johnnyAsGift.present(); // "Heeeereee's Johnny!!!"
Guest johnnyAsGuest = (Guest) johnny;
johnnyAsGuest.present(); // "Heeeereee's Johnny!!!"
}
}
上面的代码片段将编译并运行。
请注意,只有一个 @Override
必要条件!!!。这是因为Gift.present()
和Guest.present()
是“- @Override
等价的”( JLS 8.4.2)。
因此,johnny
只有一个执行的present()
,并不要紧,你如何对待johnny
,无论是作为Gift
或作为Guest
,只有一个调用方法。
这是两个不@Override
等效的继承方法的示例:
public class InterfaceTest {
interface Gift { void present(); }
interface Guest { boolean present(); }
interface Presentable extends Gift, Guest { } // DOES NOT COMPILE!!!
// "types InterfaceTest.Guest and InterfaceTest.Gift are incompatible;
// both define present(), but with unrelated return types"
}
这进一步重申,从interface
必须继承成员必须遵守成员声明的一般规则。下面我们就Gift
和Guest
定义present()
不兼容的返回类型:一个void
其他的boolean
。由于不能同时使用an void present()
和boolean present()
in 的同一原因,此示例导致编译错误。
您可以继承@Override
-equivalent的方法,但要遵循方法覆盖和隐藏的通常要求。由于它们是 @Override
等效的,因此实际上只有一种方法可以实现,因此没有区别/选择的地方。
编译器不必确定哪个方法用于哪个接口,因为一旦确定它们是 @Override
它们等效,它们就是相同的方法。
解决潜在的不兼容性可能是一项艰巨的任务,但这是另一个问题。
default
方法的Java 8
这被标记为该问题的重复/programming/24401064/understanding-and-solving-the-diamond-problems-in-java
您需要Java 8才能解决多重继承问题,但是它仍然不是diamon问题。
interface A {
default void hi() { System.out.println("A"); }
}
interface B {
default void hi() { System.out.println("B"); }
}
class AB implements A, B { // won't compile
}
new AB().hi(); // won't compile.
正如JB Nizet所说,您可以解决此问题。
class AB implements A, B {
public void hi() { A.super.hi(); }
}
但是,您没有任何问题
interface D extends A { }
interface E extends A { }
interface F extends A {
default void hi() { System.out.println("F"); }
}
class DE implement D, E { }
new DE().hi(); // prints A
class DEF implement D, E, F { }
new DEF().hi(); // prints F as it is closer in the heirarchy than A.
hi()
(以解决歧义)。例如,通过实现它作为A.super.hi()
选择来实现它的方式一样A.
就编译器而言,这两种方法是相同的。两者都有一个实现。
如果这两种方法实际上是相同的,那么这不是问题,因为这两种方法应该具有相同的实现。如果它们在合同上有所不同(根据每个接口的文档),您将遇到麻烦。
没有什么可识别的。接口仅禁止使用方法名称和签名。如果两个接口都具有名称和签名完全相同的方法,则实现类可以使用单个具体方法来实现这两个接口方法。
但是,如果两个接口方法的语义协定相互矛盾,那么您就迷失了很多。您不能在一个类中同时实现两个接口。
就像在接口中一样,我们只是在声明方法,实现这两个接口的具体类都知道只有一个方法(正如您所描述的,两个方法在返回类型中具有相同的名称)。因此应该没有问题。您将能够在具体的类中定义该方法。
但是,当两个接口的方法名称相同但返回类型不同时,您将在具体类中实现两个方法:
请看下面的代码:
public interface InterfaceA {
public void print();
}
public interface InterfaceB {
public int print();
}
public class ClassAB implements InterfaceA, InterfaceB {
public void print()
{
System.out.println("Inside InterfaceA");
}
public int print()
{
System.out.println("Inside InterfaceB");
return 5;
}
}
当编译器获取方法“ public void print()”时,它首先在InterfaceA中查找并获取。但是仍然会出现编译时错误,即返回类型与InterfaceB方法不兼容。
因此,对于编译器而言,这很麻烦。
这样,您将无法实现具有相同名称但返回类型不同的方法的两个接口。