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

Jot*_*thi 223 java overriding interface

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

例如:

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;
  }
}   
Run Code Online (Sandbox Code Playgroud)

pol*_*nts 312

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


兼容性示例

这里有一个例子,你有interface Gift一个present()方法(如,赠送礼物),interface Guest还有一个present()方法(如客人存在且不存在).

Presentable johnny既是a Gift又是a 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!!!"
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码片段编译并运行.

请注意,只有一个 @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"
}
Run Code Online (Sandbox Code Playgroud)

这进一步重申,继承成员interface必须遵守成员声明的一般规则.下面我们就GiftGuest定义present()不兼容的返回类型:一个void其他的boolean.出于同样的原因,您不能使用void present()boolean present()在一种类型中,此示例会导致编译错误.


摘要

您可以继承@Override等效的方法,这取决于方法覆盖和隐藏的常规要求.因为它们 @Override等价的,所以实际上只有一种方法可以实现,因此没有什么可以区分/选择的.

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

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

参考

  • BTW在Java 8中对`default`方法的支持稍有改动. (2认同)
  • 我是一名 Java 开发人员,但 C# 在这方面确实更聪明:/sf/ask/165982491/ (2认同)

Pet*_*rey 22

这被标记为此问题的副本/sf/ask/1708074511/

您需要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.
Run Code Online (Sandbox Code Playgroud)

正如JB Nizet的评论,你可以解决这个问题.

class AB implements A, B {
    public void hi() { A.super.hi(); }
}
Run Code Online (Sandbox Code Playgroud)

但是,你没有问题

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.
Run Code Online (Sandbox Code Playgroud)

  • 为了在不破坏 60% 的代码库的情况下向接口(特别是集合接口)添加新方法。 (3认同)
  • @PeterLawrey:AB不会编译,因为它必须覆盖`hi()`(以修复歧义).例如,通过将其实现为`A.super.hi()`来选择以与A相同的方式实现它. (3认同)

Ash*_*Ash 20

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

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

  • 它解释了为什么Java不允许您“扩展”超过一个类 (2认同)

Mic*_*rdt 12

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

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


Pau*_*lan 5

好吧,如果它们都是一样的,那没关系。它通过每个接口方法使用一个具体方法来实现这两个方法。


小智 5

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

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

请看下面的代码:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

当编译器获取方法“public void print()”时,它首先在 InterfaceA 中查找并获取它。但它仍然给出编译时错误,即返回类型与 InterfaceB 的方法不兼容。

所以它对编译器来说是一团糟。

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