Wenn ein Typ zwei Schnittstellen implementiert und jede Schnittstelle eine Methode definiert, die eine identische Signatur hat, dann gibt es effektiv nur eine Methode und sie sind nicht unterscheidbar. Wenn beispielsweise die beiden Methoden inkompatible Rückgabetypen haben, wird es zu einem Kompilierfehler. Dies ist die allgemeine Regel für Vererbung, Methodenüberschreibung, Verdeckung und Deklarationen und gilt auch für mögliche Konflikte nicht nur zwischen 2 geerbten Schnittstellenmethoden, sondern auch zwischen einer Schnittstelle und einer übergeordneten Klassenmethode oder sogar nur Konflikte aufgrund der Typlöschung von Generika.
Kompatibilitätsbeispiel
Hier ist ein Beispiel, bei dem Sie eine Schnittstelle Geschenk haben, die eine present() Methode hat (als Geschenke präsentieren) und auch eine Schnittstelle Gast haben, die ebenfalls eine present() Methode hat (als Gast anwesend und nicht abwesend ist).
Geschenkbarer Johnny ist sowohl ein Geschenk als auch ein Gast.
public class InterfaceTest {
interface Geschenk { void present(); }
interface Gast { void present(); }
interface Vorzeigbares extends Geschenk, Gast { }
public static void main(String[] args) {
Vorzeigbares johnny = new Vorzeigbares() {
@Override public void present() {
System.out.println("Heeeereee's Johnny!!!");
}
};
johnny.present(); // "Heeeereee's Johnny!!!"
((Geschenk) johnny).present(); // "Heeeereee's Johnny!!!"
((Gast) johnny).present(); // "Heeeereee's Johnny!!!"
Geschenk johnnyAlsGeschenk = (Geschenk) johnny;
johnnyAlsGeschenk.present(); // "Heeeereee's Johnny!!!"
Gast johnnyAlsGast = (Gast) johnny;
johnnyAlsGast.present(); // "Heeeereee's Johnny!!!"
}
}
Der obige Ausschnitt wird kompiliert und ausgeführt.
Beachten Sie, dass nur ein @Override erforderlich ist!!!. Dies liegt daran, dass Geschenk.present() und Gast.present() "@Override-äquivalent" sind (JLS 8.4.2).
Daher hat Johnny nur eine Implementierung von present() und es spielt keine Rolle, wie Sie Johnny behandeln, ob als Geschenk oder als Gast, es gibt nur eine Methode, die aufgerufen werden kann.
Inkompatibilitätsbeispiel
Hier ist ein Beispiel, in dem die beiden geerbten Methoden NICHT @Override-äquivalent sind:
public class InterfaceTest {
interface Geschenk { void present(); }
interface Gast { boolean present(); }
interface Vorzeigbares extends Geschenk, Gast { } // KOMPILIERT NICHT!!!
// "Typen InterfaceTest.Gast und InterfaceTest.Geschenk sind nicht kompatibel;
// beide definieren present(), aber mit nicht verwandten Rückgabetypen"
}
Dies unterstreicht weiterhin, dass das Erben von Elementen aus einer Schnittstelle der allgemeinen Regel für Elementdeklarationen entsprechen muss. Hier definieren Geschenk und Gast present() mit unvereinbaren Rückgabetypen: ein void und ein boolean. Aus demselben Grund, aus dem Sie keine void present() und eine boolean present() in einem Typ haben können, führt dieses Beispiel zu einem Kompilierfehler.
Zusammenfassung
Sie können Methoden erben, die @Override-äquivalent sind, unterliegen den üblichen Anforderungen für Methodenüberschreibung und -verdeckung. Da sie @Override-äquivalent sind, gibt es effektiv nur eine Methode zu implementieren, und daher gibt es nichts zu unterscheiden/auszuwählen.
Der Compiler muss nicht identifizieren, welche Methode für welche Schnittstelle ist, denn sobald sie als @Override-äquivalent bestimmt werden, handelt es sich um dieselbe Methode.
Die Behebung möglicher Inkompatibilitäten kann eine knifflige Aufgabe sein, aber das ist ein ganz anderes Thema.
Referenzen
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.4