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

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

例:

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;
}
}
233564 次浏览

如果它们都是一样的,那就无所谓了。它通过每个接口方法一个具体的方法来实现这两种方法。

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

如果这两个方法实际上是相同的,这就不是问题,因为它们应该有相同的实现。如果它们在合同上是不同的(根据每个接口的文档),那么您就有麻烦了。

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

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

如果一个类型实现了两个接口,并且每个interface定义了一个具有相同签名的方法,那么实际上只有一个方法,并且它们是不可区分的。如果这两个方法有冲突的返回类型,那么这将是一个编译错误。这是继承、方法重写、隐藏和声明的一般规则,不仅适用于两个继承的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()是“__abc0等效的”(JLS 8.4.2)。

因此,johnnypresent()只有一个实现,无论你如何处理johnny,无论是作为Gift还是作为Guest,都只有一个方法可以调用。


不相容的例子

下面是一个例子,其中两个继承的方法不是__abc0等效的:

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(),这个例子会导致编译错误。


总结

你可以继承与__abc0等价的方法,这取决于方法覆盖和隐藏的通常要求。由于它们 __abc0等价,实际上只有一个方法可以实现,因此没有什么可以区分/选择的。

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

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

参考文献

尝试将接口实现为匿名。

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


}


}

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

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

请看下面的代码:

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

所以编译器就乱套了。

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

这被标记为这个问题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.

还可以采用以下两种方法来实现重复的方法并避免歧义-

<标题>方法1:< / h1 >

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:< / h1 >

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