使用相同的方法在类中实现两个接口。覆盖哪种接口方法?

时间:2010-05-10 10:21:34

标签: java interface override

两个具有相同方法名称和签名的接口。但是由单个类实现,然后编译器将如何识别哪个方法适用于哪个接口?

例如:

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;
  }
}   

7 个答案:

答案 0 :(得分:291)

如果一个类型实现了两个接口,并且每个interface定义了一个具有相同签名的方法,那么实际上只有一个方法,并且它们是不可区分的。例如,如果两种方法具有冲突的返回类型,那么它将是编译错误。这是继承,方法重写,隐藏和声明的一般规则,并且不仅适用于2个继承的interface方法之间的可能冲突,还适用于interface和超级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继承成员必须遵守成员声明的一般规则。在这里,我们GiftGuest定义present(),返回类型不兼容:一个void另一个boolean。出于同样的原因,您不能在一种类型中使用void present()boolean present(),此示例会导致编译错误。


摘要

您可以继承@Override - 等效的方法,这取决于方法覆盖和隐藏的常规要求。由于它们 ARE @Override - 等效,因此实际上只有一种方法可以实现,因此无需区分/选择。

编译器不必识别哪个接口的方法,因为一旦确定它们是@Override - 等效,它们就是相同的方法。

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

参考

答案 1 :(得分:20)

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

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

答案 2 :(得分:19)

这被标记为此问题的重复https://stackoverflow.com/questions/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.

答案 3 :(得分:11)

没有什么可以识别的。接口仅禁止方法名称和签名。如果两个接口都有一个完全相同的名称和签名的方法,那么实现类可以用一个具体的方法实现这两个接口方法。

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

答案 4 :(得分:4)

尝试以匿名方式实现界面。

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(){

}

}

答案 5 :(得分:4)

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

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

请看下面的代码:

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的方法不兼容。

因此编译器会变得混乱。

通过这种方式,您将无法实现具有相同名称但返回类型不同的方法的两个接口。

答案 6 :(得分:3)

如果它们都是相同的那么无所谓。它通过每个接口方法使用单个具体方法实现它们。