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

2022-08-31 05:16:17

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

前任:

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

答案 1

如果一个类型实现两个接口,并且每个接口定义一个具有相同签名的方法,则实际上只有一个方法,并且它们不可区分。例如,如果这两种方法具有冲突的返回类型,则将是编译错误。这是继承、方法重写、隐藏和声明的一般规则,并且不仅适用于 2 个继承的方法之间可能存在的冲突,还适用于一个和一个超级方法之间可能的冲突,甚至只是由于泛型的类型擦除而发生的冲突。interfaceinterfaceinterfaceclass


兼容性示例

这里有一个例子,你有一个,它有一个方法(如,赠送礼物),还有一个,它也有一个方法(如,来宾在场而不是缺席)。interface Giftpresent()interface Guestpresent()

Presentable johnny既是 a 又是 .GiftGuest

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!!!"
    }
}

上面的代码段将编译并运行。

请注意,只有一个必要!!!。这是因为 并且是“等效的”(JLS 8.4.2)。@OverrideGift.present()Guest.present()@Override

因此,只有 一个 实现,无论你如何对待,无论是作为 a 还是作为 a,都只有一个可以调用的方法。johnnypresent()johnnyGiftGuest


不兼容示例

下面是一个示例,其中两个继承的方法不是等效的:@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"
}

这进一步重申,从一个继承成员必须遵守成员声明的一般规则。在这里,我们有并定义了不兼容的返回类型:一个是另一个。出于不能和 a in 一种类型的原因相同,此示例会导致编译错误。interfaceGiftGuestpresent()voidbooleanvoid present()boolean present()


总结

您可以继承等效的方法,但要遵守方法重写和隐藏的通常要求。由于它们是等效的,因此实际上只有一种方法可以实现,因此没有什么可区分/选择的。@Override@Override

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

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

引用


答案 2

这被标记为与此问题重复 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.