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

Ex:

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:

App.java -

public class App {
    public static void main(String[] args) {
        TestInterface1 testInterface1 = new TestInterface1();
        TestInterface2 testInterface2 = new TestInterface2();
        testInterface1.draw();
        testInterface2.draw();
    }
}

TestInterface1.java -

public class TestInterface1 implements Circle {
    
}

TestInterface2.java -

public class TestInterface2 implements Rectangle {
    
}

Circle.java -

public interface Circle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing circle");
    }
}

Rectangle.java -

public interface Rectangle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing rectangle");
    }
}

Drawable.java -

public interface Drawable {
    default void draw() {
        System.out.println("Drawing");
    }
}

输出-

Drawing circle
Drawing rectangle

方法2:

App.java -

public class App {
    public static void main(String[] args) {
        
        Circle circle = new Circle() {
                
        };
        Rectangle rectangle = new Rectangle() {
                
        };

        circle.draw();
        rectangle.draw();
    }
}

Circle.java -

public interface Circle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing circle");
    }
}

Rectangle.java -

public interface Rectangle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing rectangle");
    }
}

Drawable.java -

public interface Drawable {
    default void draw() {
        System.out.println("Drawing");
    }
}

输出-

Drawing circle
Drawing rectangle

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

然而,如果这两个接口方法的语义契约是矛盾的,那么你就输了;这样你就不能在一个类中实现两个接口。

If a type implements two interfaces, and each interface define a method that has identical signature, then in effect there is only one method, and they are not distinguishable. If, say, the two methods have conflicting return types, then it will be a compilation error. This is the general rule of inheritance, method overriding, hiding, and declarations, and applies also to possible conflicts not only between 2 inherited interface methods, but also an interface and a super class method, or even just conflicts due to type erasure of generics.


兼容性的例子

下面是一个例子,其中有一个接口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等效的”(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"
}

这进一步重申了从接口继承成员必须遵守成员声明的一般规则。这里Gift和Guest定义的present()返回类型不兼容:一个为void,另一个为boolean。由于同样的原因,你不能在一个类型中使用void present()和boolean present(),这个例子会导致编译错误。


总结

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

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

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

参考文献

JLS 8.4.2方法签名 JLS 8.4.8继承、重写和隐藏 JLS 8.4.8.3覆盖和隐藏的要求 JLS 8.4.8.4继承具有重写等效签名的方法 一个类可以继承多个具有重写等效签名的方法。