Java不允许多重继承来保护钻石问题。它使用接口来处理这个问题。
然后使用界面的情况,假设
interface A{
run();
}
interface B{
run();
}
class C implements A, B{
run() {} //Which interface we are using?
}
当我们在课程run()
中调用方法C
时,我们如何确定我们使用的是哪个界面?
答案 0 :(得分:10)
你没有。并不重要,因为实现不是在接口上而是在类上。所以实施是独一无二的。没有歧义。
重要的是,如果每个声明都想要具有不同的返回类型:
interface A{
void run();
}
interface B{
String run();
}
class C implements A, B{
???? run() {}
}
这是Java中多个接口出现问题的唯一方法。
答案 1 :(得分:7)
没关系。接口的目的是指示类C具有方法run()。你可以依赖那种方法。
即使A和B都指定了run方法,它也只实现一次,因此没有冲突。
当您说您正在使用界面时,它实际上意味着如何声明对象:
A myobject = new C();
myobject.run();
VS
B myObject = new C();
myobject.run();
在第一种情况下,您正在“使用”A接口,也就是说,您的代码假设myobject对象属于A类,并且它有一个名为run()的方法。在第二种情况下,您正在“使用”界面B.
答案 2 :(得分:2)
如果一个类型实现了两个接口,并且每个接口定义了一个具有相同签名的方法,那么实际上只有一个方法,并且它们是不可区分的。例如,如果两种方法具有冲突的返回类型,那么它将是编译错误。这是继承,方法重写,隐藏和声明的一般规则,并且还适用于不仅可能在2个继承的接口方法之间发生冲突,还可以应用于接口和超类方法之间的冲突,甚至只是由于泛型的类型擦除引起的冲突
兼容性示例
这是一个示例,其中您有一个接口Gift,它有一个present()方法(如,呈现礼物),还有一个接口Guest,它也有一个present()方法(如,客人存在)而不是缺席。)
表现出来的约翰尼既是礼物又是嘉宾。
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-equivalent”(JLS 8.4.2)。
因此,johnny只有一个present()的实现,无论你如何对待johnny,无论是作为礼物还是作为访客,只有一种方法可以调用。
不兼容的例子
这是一个示例,其中两个继承的方法是NOT @ Override-equivalent:
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"
}
这进一步重申,从接口继承成员必须遵守成员声明的一般规则。这里我们有Gift和Guest定义带有不兼容返回类型的present():一个void另一个boolean。出于同样的原因,你不能在一个类型中使用void present()和一个boolean present(),这个例子会导致编译错误。
摘要
您可以继承@ Override-equivalent的方法,这取决于方法覆盖和隐藏的常规要求。由于它们是ARE @ Override等效的,实际上只有一种方法可以实现,因此无需区分/选择。
编译器不必识别哪个接口的方法,因为一旦确定它们是@Override-equivalent,它们就是相同的方法。
解决潜在的不兼容问题可能是一项棘手的任务,但这完全是另一个问题。
参考
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.4
答案 3 :(得分:1)
即使使用相同的方法声明实现多个接口,您的类中也只有该方法的一个定义。所以,这里没有任何歧义,因为只有一种方法可以调用。
答案 4 :(得分:1)
你不能说;但是它也没关系,因为接口没有功能。
当Java 8出现时,这会稍微改变,因为接口可以具有默认的函数实现;如果有多个默认实现,则可能存在不确定性。如何解决这个问题在问题Are defaults in JDK 8 a form of multiple inheritance in Java?中解释。
答案 5 :(得分:0)
你的问题没有多大意义。我们来看一个现实的例子吧。 Human
可能会哭。 AnimalBaby
可能会哭。现在你有一个实例John
,它既是人类又是AnimalBaby,你会让它哭泣。怎么了? John
哭了。它实现两个接口的cry()
方法的事实并没有改变哭声对John的意义和作用。
答案 6 :(得分:0)
两者。 C从两个接口继承了两个方法(恰好是覆盖等效的(8.4.8.4))。 C然后有一个覆盖两者的方法,因为签名匹配两者。 (8.4.2)
然而,人们可能想知道 - 仅仅因为两个方法具有相同的名称和参数类型,并不一定意味着它们具有相同的语义。这个名字很可能是一个英文单词,意思是两个不同的东西。如果我们从两个看起来相同但实际上在语义上不同的超级接口继承了两个方法,那么在子类中应该有两个实现呢?例如
interface java.lang.Runnable
void run()
interface com.animal.Runnable
void run()
class Dog implements com.animal.Runnable,
java.lang.Runnable // a dog as a task
???
我们可以想象一种能够处理这种情况的语言。但是Java没有这样做。如果两个方法足够相似,则假定它们具有相同的语义。幸运的是,在实践中,这似乎确实是一个问题。