Wenn ein Typ zwei Schnittstellen implementiert und jeweils interface
eine Methode mit identischer Signatur definiert, gibt es tatsächlich nur eine Methode, und sie sind nicht unterscheidbar. Wenn die beiden Methoden beispielsweise widersprüchliche Rückgabetypen haben, liegt ein Kompilierungsfehler vor. Dies ist die allgemeine Regel für Vererbung, Überschreiben, Ausblenden und Deklarieren von interface
Methoden und gilt auch für mögliche Konflikte nicht nur zwischen zwei geerbten Methoden, sondern auch für eine interface
und eine Supermethode class
oder auch nur für Konflikte aufgrund der Typlöschung von Generika.
Kompatibilitätsbeispiel
Hier ist ein Beispiel, in dem Sie eine haben interface Gift
, die eine present()
Methode hat (wie in, Geschenke präsentieren), und auch eine interface Guest
, die auch eine present()
Methode hat (wie in, der Gast ist anwesend und nicht abwesend).
Presentable johnny
ist sowohl a Gift
als auch 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!!!"
}
}
Das obige Snippet wird kompiliert und ausgeführt.
Beachten Sie, dass nur eine @Override
erforderlich ist !!! . Dies liegt daran, dass Gift.present()
und Guest.present()
" @Override
äquivalent" sind ( JLS 8.4.2 ).
Es gibt also johnny
nur eine Implementierung von present()
, und es spielt keine Rolle, wie Sie behandeln johnny
, ob als Gift
oder als Guest
, es gibt nur eine Methode, die aufgerufen werden kann.
Beispiel für Inkompatibilität
Hier ist ein Beispiel, in dem die beiden geerbten Methoden NICHT @Override
-äquivalent sind:
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"
}
Dies bekräftigt weiter, dass das Erben von Mitgliedern von a interface
die allgemeine Regel der Mitgliedererklärungen befolgen muss. Hier haben wir Gift
und Guest
definieren present()
mit inkompatiblen Rückgabetypen: eine void
der anderen boolean
. Aus dem gleichen Grund, aus dem Sie ein void present()
und ein boolean present()
in einem Typ nicht können, führt dieses Beispiel zu einem Kompilierungsfehler.
Zusammenfassung
Sie können Methoden erben, die @Override
-äquivalent sind, vorbehaltlich der üblichen Anforderungen zum Überschreiben und Ausblenden von Methoden. Da sie SIND @Override
-Äquivalent, effektiv ist es nur eine Methode zu implementieren, und somit gibt es nichts zu unterscheiden / Auswahl.
Der Compiler muss nicht identifizieren, welche Methode für welche Schnittstelle @Override
geeignet ist , da sie, sobald festgestellt wurde, dass sie gleichwertig sind, dieselbe Methode sind.
Das Beheben potenzieller Inkompatibilitäten mag eine schwierige Aufgabe sein, aber das ist insgesamt ein anderes Problem.
Verweise
default
Methoden in Java 8.Foo
undBar
. Grundsätzlich muss Ihre Klasse beispielsweise eine der Schnittstellen implementierenFoo
und eineBar asBar()
Methode bereitstellen , um eine innere Klasse zurückzugeben, die die zweiteBar
Schnittstelle implementiert . Nicht perfekt, da Ihre Klasse letztendlich keine "Bar" ist, aber unter bestimmten Umständen nützlich sein kann.Dies wurde als Duplikat dieser Frage markiert: /programming/24401064/understanding-and-solving-the-diamond-problems-in-java
Sie benötigen Java 8, um ein Mehrfachvererbungsproblem zu erhalten, aber es ist immer noch kein Diamonproblem als solches.
Wie JB Nizet kommentiert, können Sie dieses Problem beheben.
Sie haben jedoch kein Problem mit
quelle
hi()
(um die Mehrdeutigkeit zu beheben). Zum Beispiel, indem Sie es soA.super.hi()
implementieren, dass es auf die gleiche Weise wie A. implementiert wird.Für den Compiler sind diese beiden Methoden identisch. Es wird eine Implementierung von beiden geben.
Dies ist kein Problem, wenn die beiden Methoden effektiv identisch sind, da sie dieselbe Implementierung haben sollten. Wenn sie vertraglich unterschiedlich sind (gemäß der Dokumentation für jede Schnittstelle), sind Sie in Schwierigkeiten.
quelle
Es gibt nichts zu identifizieren. Schnittstellen verbieten nur einen Methodennamen und eine Signatur. Wenn beide Schnittstellen eine Methode mit genau demselben Namen und derselben Signatur haben, kann die implementierende Klasse beide Schnittstellenmethoden mit einer einzigen konkreten Methode implementieren.
Wenn jedoch die semantischen Verträge der beiden Schnittstellenmethoden widersprüchlich sind, haben Sie ziemlich viel verloren. Sie können dann nicht beide Schnittstellen in einer Klasse implementieren.
quelle
Versuchen Sie, die Schnittstelle anonym zu implementieren.
quelle
Wie in der Schnittstelle deklarieren wir nur Methoden. Eine konkrete Klasse, die diese beiden Schnittstellen implementiert, versteht, dass es nur eine Methode gibt (wie Sie beschrieben haben, haben beide den gleichen Namen im Rückgabetyp). Es sollte also kein Problem damit geben. Sie können diese Methode in einer konkreten Klasse definieren.
Wenn jedoch zwei Schnittstellen eine Methode mit demselben Namen, aber unterschiedlichem Rückgabetyp haben und Sie zwei Methoden in einer konkreten Klasse implementieren:
Bitte schauen Sie sich den folgenden Code an:
Wenn der Compiler die Methode "public void print ()" erhält, sucht er zuerst in InterfaceA und erhält sie. Trotzdem gibt er einen Fehler bei der Kompilierung, dass der Rückgabetyp nicht mit der Methode von InterfaceB kompatibel ist.
Für den Compiler geht es also durcheinander.
Auf diese Weise können Sie nicht zwei Schnittstellen mit derselben Methode, sondern unterschiedlichem Rückgabetyp implementieren.
quelle
Nun, wenn beide gleich sind, spielt es keine Rolle. Beide werden mit einer einzigen konkreten Methode pro Schnittstellenmethode implementiert.
quelle