从两个不同的接口调用相同的方法名-Java

从两个不同的接口调用相同的方法名-Java,java,class,interface,abstract,diamond-problem,Java,Class,Interface,Abstract,Diamond Problem,Java不允许多重继承来保护菱形问题。它使用接口来解决这个问题 那么使用接口的情况呢,比方说 interface A{ run(); } interface B{ run(); } class C implements A, B{ run() {} //Which interface we are using? } 当我们在类C中调用方法run()时,我们如何确定正在使用哪个接口?您不知道。这并不重要,因为实现不是在接口上,而是在类上。因此,实现是独特的。没有歧义 重要的是,如果每个声

Java不允许多重继承来保护菱形问题。它使用接口来解决这个问题

那么使用接口的情况呢,比方说

interface A{
run();
}

interface B{
run();
}

class C implements A, B{
run() {}   //Which interface we are using?
}

当我们在类
C
中调用方法
run()
时,我们如何确定正在使用哪个接口?

您不知道。这并不重要,因为实现不是在接口上,而是在类上。因此,实现是独特的。没有歧义

重要的是,如果每个声明想要有不同的返回类型:

interface A{
    void run();
}

interface B{
    String run();
}

class C implements A, B{
    ???? run() {}
}

这是Java中多个接口出现问题的唯一方法。

这无关紧要。接口的目的是指示类C有一个run()方法。你可以相信那种方法就在那里

尽管A和B都指定了run方法,但它只实现一次,因此没有冲突

当你说你正在使用一个接口时,它实际上意味着你的对象是如何声明的:

   A myobject = new C();
   myobject.run();
vs


在第一种情况下,您正在“使用”A接口,也就是说,您的代码假设myobject对象是A类型,并且它有一个名为run()的方法。在第二种情况下,您正在“使用”接口B。

即使您使用相同的方法声明实现多个接口,您的类中也只有该方法的一个定义。因此,这里没有任何歧义,因为只有一种方法可以调用。

您的问题没有多大意义。让我们举一个现实的例子。人类会哭。
AnimalBaby
会哭。现在你有了一个实例
John
,它既是人类又是动物,你让它哭了。会发生什么<约翰哭了。它实现了两个接口的
cry()
方法这一事实并没有改变cry对John的意义和作用。

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

兼容性示例

下面是一个示例,其中有一个接口Gift,它有一个present()方法(如中的presenting gives),还有一个接口Guest,它也有一个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()是“@覆盖等效”(JLS 8.4.2)

因此,johnny只有一个present()的实现,无论您如何对待johnny,无论是作为礼物还是作为来宾,都只有一个方法可以调用

不兼容示例

下面是一个示例,其中两个继承的方法并不@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 define present(),返回类型不兼容:一个为void,另一个为boolean。出于不能在一种类型中使用void present()和boolean present()的相同原因,此示例会导致编译错误

总结

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

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

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

参考资料


你说不出来;然而,这也不重要,因为接口没有任何功能


当Java8问世时,这一点会有轻微的改变,因为接口可以有默认的函数实现;如果有多个默认实现,那么可能存在歧义。问题中解释了如何解决这一问题。

两者都有。C从两个接口继承了两个方法(这两个接口恰好是等价的)。C然后有一个方法覆盖这两个,因为签名匹配这两个

然而,有人可能会想,仅仅因为两个方法具有相同的名称和参数类型,并不一定意味着它们具有相同的语义。这个名字很可能是一个英语单词,意思是两个不同的东西。如果我们从两个超级接口继承了两个方法,它们看起来相同,但实际上语义不同,那么子类中应该有两个实现?比如说

interface java.lang.Runnable
    void run()

interface com.animal.Runnable
    void run()

class Dog implements com.animal.Runnable,
                     java.lang.Runnable // a dog as a task
    ???

我们可以想象一种语言能够处理这种情况。但Java并没有做到这一点。如果两种方法足够相似,则假定它们具有相同的语义。幸运的是,实际上这似乎是个问题。

而且更重要的是,这并不重要。请注意,您的方法声明中目前没有返回类型。如果两个接口
run
方法声明了不兼容的返回类型,您将无法实现该接口。接口是契约,并且根本没有(实现)代码。换句话说:您正在声明一个必须在其他地方实现的“名称”。在C类中,您必须运行()方法,一个是void,一个是String。如果两者都有void返回类型呢?更重要的是,如果返回类型也相同,那么我认为它遵循先到先的原则
interface java.lang.Runnable
    void run()

interface com.animal.Runnable
    void run()

class Dog implements com.animal.Runnable,
                     java.lang.Runnable // a dog as a task
    ???