用同样的方法在一个类中实现两个接口。 哪个接口方法被覆盖?

两个接口具有相同的方法名称和签名。 但是由一个类实现,那么编译器将如何识别哪个接口是哪个方法?

例如:

interface A{ int f(); } interface B{ int f(); } class Test implements A, B{ public static void main(String... args) throws Exception{ } @Override public int f() { // from which interface A or B return 0; } } 

如果一个types实现了两个接口,并且每个interface定义了一个具有相同签名的方法,那么实际上只有一个方法,并且它们是不可区分的。 如果说,这两种方法有冲突的返回types,那么这将是一个编译错误。 这是inheritance,方法重写,隐藏和声明的一般规则,也适用于不仅在2个inheritance的interface方法之间,而且也在interface和超class方法之间的可能冲突,甚至仅适用于genericstypes擦除的冲突。


兼容性示例

下面是一个例子,其中有一个interface Gift ,它有一个present()方法(如in,呈现礼物),还有一个interface Guest ,它也有一个present()方法(如in,guest是存在的并且不存在)。

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()是“ Guest.present() ”( JLS 8.4.2 )。

因此, johnny 只有一个 present() 实现 ,不pipe你如何对待johnny ,无论是作为Gift还是作为Guest ,只有一个方法可以调用。


不兼容的例子

下面是两个inheritance的方法不是@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" } 

这进一步重申,从interfaceinheritance成员必须遵守成员声明的一般规则。 这里我们有GiftGuest定义present()与不兼容的返回types:一个void另一个boolean 。 出于同样的原因,你不能在一个types中boolean present()一个void present()和一个boolean present() ,这个例子会导致编译错误。


概要

您可以inheritance@Override -equivalent的方法,但要遵守方法覆盖和隐藏的通常要求。 由于它们 @Override -equivalent,所以实际上只有一种方法可以实现,因此没有任何区分/select。

编译器不需要确定哪个接口是哪个方法,因为一旦它们被确定为@Override -equivalent,它们是相同的方法。

解决潜在的不兼容可能是一个棘手的任务,但这完全是另一个问题。

参考

  • JLS 8.4.2方法签名
  • JLS 8.4.8inheritance,重写和隐藏
  • JLS 8.4.8.3覆盖和隐藏的要求
  • JLS 8.4.8.4用Override-Equivalent签名inheritance方法
    • “一个类可以通过覆盖等价签名来inheritance多个方法。”

就编译器而言,这两种方法是相同的。 两者都会有一个实现。

如果两种方法实际上是相同的,那么这不是问题,因为它们应该具有相同的实现。 如果它们在合同上有所不同(按照每个界面的文档),您将遇到麻烦。

这被标记为这个问题的重复https://stackoverflow.com/questions/24401064/understanding-and-solving-the-diamond-problems-in-java

你需要Java 8来获得多重inheritance的问题,但它仍然不是一个直接的问题。

 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. 

没有什么可以确定的。 接口只禁止方法名称和签名。 如果两个接口都有完全相同名称和签名的方法,则实现类可以使用单个具体方法来实现这两种接口方法。

但是,如果两种界面方法的语义契约是矛盾的,那么你几乎失去了; 那么你不能在一个类中实现两个接口。

尝试以匿名方式实现接口。

 public class MyClass extends MySuperClass implements MyInterface{ MyInterface myInterface = new MyInterface(){ /* Overrided method from interface */ @override public void method1(){ } }; /* Overrided method from superclass*/ @override public void method1(){ } } 

在接口中,我们只是声明方法,实现这两个接口的具体类理解是只有一个方法(正如你所描述的,在返回types中都有相同的名字)。 所以不应该有一个问题,你可以在具体的类中定义该方法。

但是当两个接口有一个名字相同但返回types不同的方法时,在具体的类中实现了两个方法:

请看下面的代码:

 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中查找并获取它。但是仍然给编译时错误,即返回types与InterfaceB的方法不兼容。

所以它对编译器来说是不合适的。

这样,你将无法实现两个接口有相同名称但返回types不同的方法。

那么如果他们都是一样的没关系。 它使用每个接口方法的一个具体方法来实现它们。