Sind Standardeinstellungen in JDK 8 eine Form der Mehrfachvererbung in Java?

83

Mit einer neuen Funktion in JDK 8 können Sie eine vorhandene Schnittstelle erweitern und gleichzeitig die Binärkompatibilität beibehalten.

Die Syntax ist wie

public interface SomeInterface() {
  void existingInterface();
  void newInterface() default SomeClass.defaultImplementation;
}

Auf diese Weise SomeInterfacetreten bei allen vorhandenen Implementierungen beim Upgrade auf diese neue Version nicht alle plötzlich Kompilierungsfehler auf newInterface().

Was passiert, wenn Sie zwei Schnittstellen implementieren, die beide eine neue Standardmethode hinzugefügt haben, die Sie nicht implementiert haben? Lassen Sie mich anhand eines Beispiels erklären.

public interface Attendance {
   boolean present() default DefaultAttendance.present;
}

public interface Timeline {
   boolean present() default DefaultTimeline.present;
}

public class TimeTravelingStudent implements Attendance, Timeline {

}

// which code gets called?
new TimeTravelingStudent().present();

Wurde dies bereits als Teil von JDK 8 definiert?

Ich fand die Java-Götter, die hier über etwas Ähnliches sprachen: http://cs.oswego.edu/pipermail/lambda-lib/2011-February/000068.html , aber es ist Teil der privaten Mailingliste und ich kann sie nicht direkt fragen.

Weitere Informationen zur Verwendung der Standardeinstellungen in JDK 8 und zur Erweiterung der Collection-Oberfläche zur Unterstützung von Lambdas finden Sie hier: https://oracleus.wingateweb.com/published/oracleus2011/sessions/25066/25066_Cho223662.pdf

Pyrolistisch
quelle
Die zu sehende Videositzung ist hier medianetwork.oracle.com/video/player/1113272518001 Dies ist der Designer, der über die Funktion namens Virtuelle Erweiterungen spricht. Er spricht auch darüber, wie dies die Abwärtskompatibilität nicht beeinträchtigt.
Peter Lawrey
Die Antwort auf mein Beispiel lautet also, dass Sie derzeit einen Compilerfehler erhalten. Sie sind aber offen für andere Lösungen.
Pyrolistical
Ein weiteres nützliches Material dafür ist cr.openjdk.java.net/~briangoetz/lambda/…
MohamedSanaulla
Nebenbemerkung: Die endgültige Syntax für Standardimplementierungen von Schnittstellenmethoden stellte sich als unterschiedlich heraus (Codeblock anstelle eines Verweises auf eine externe Klasse).
Joachim Sauer
4
Java hatte schon immer mehrere Vererbungen von Typen . Standardmethoden fügen eine Mehrfachvererbung des Verhaltens hinzu , jedoch nicht des Status . (Mehrfache Vererbung von Status in Sprachen wie C ++ ist der Grund für die meisten Probleme.)
Brian Goetz

Antworten:

66

Die Antwort auf die doppelte Operation lautet:

Um das Problem der Mehrfachvererbung zu lösen, muss eine Klasse, die zwei Schnittstellen implementiert, die eine Standardimplementierung für denselben Methodennamen und dieselbe Signatur bereitstellen, eine Implementierung der Methode bereitstellen. [Kompletter Artikel]

Meine Antwort auf Ihre Frage lautet: Ja, es handelt sich um eine Form der Mehrfachvererbung, da Sie Verhalten von verschiedenen Eltern erben können. Was fehlt, ist das Erben von Zuständen, dh Attributen.

H-Man2
quelle
2
+1: Wenn es einen Konflikt gibt, wird eine spezifischere Implementierung gegenüber einer weniger spezifischen erforderlich sein, sodass Sie angeben können, welche es sein soll, wenn es einen Konflikt gibt.
Peter Lawrey
@ H-Man2 Ich verstehe es nicht. Wenn dies zutrifft, bedeutet dies, dass die Binärkompatibilität beeinträchtigt wird. Vielleicht ist das gar nicht so schlimm, als würde man die Binärkompatibilität brechen, um Mehrfachvererbung zu verhindern.
Pyrolistical
@ PeterLawrey welches ist in meinem Beispiel spezifischer?
Pyrolistical
@Pyrolistical: Nein, die Kompatibilität wird nicht beeinträchtigt, da der Compiler die Standardimplementierung in einen normalen Methodenaufruf übersetzen kann. Ich denke, es ist eher ein Makro als eine echte Vererbung, kann aber Aspekte der Mehrfachvererbung simulieren. Vielleicht liefert das Video von Peter eine detailliertere Antwort.
H-Man2
Tatsächlich
8

Ich weiß, dass dies ein alter Beitrag ist, aber da ich mit diesem Zeug arbeite ...

Sie erhalten einen Fehler vom Compiler, der Ihnen Folgendes mitteilt:

 Die Klasse TimeTravelingStudent erbt nicht verwandte Standardeinstellungen für present () von den Typen Attendance und Timeline. Der Verweis auf present ist nicht eindeutig. Sowohl die Methode present () in der Timeline als auch die Methode present () in Attendance stimmen überein.

Enkk
quelle
7

Es gibt zwei Szenarien:

1) Zunächst wurde erwähnt, dass es keine spezifischste Schnittstelle gibt

public interface A {
   default void doStuff(){ /* implementation */ }
}

public interface B {
   default void doStuff() { /* implementation */ } 
}

public class C implements A, B {
// option 1: own implementation
// OR
// option 2: use new syntax to call specific interface or face compilation error
  void doStuff(){
      B.super.doStuff();
  }
}

2) Zweitens, wenn es eine spezifischere Schnittstelle gibt:

   public interface A {
       default void doStuff() { /* implementation */ } 
    }

    public interface B extends A {
       default void doStuff() { /* implementation */ } 
    }

    public class C implements A, B {
    // will use method from B, as it is "closer" to C
    }
Andrejs
quelle
4

Meine Antwort auf Ihre Frage lautet: Ja, es handelt sich um eine Form der Mehrfachvererbung, da Sie Verhalten von verschiedenen Eltern erben können. Was fehlt, ist das Erben von Zuständen, dh Attributen.

Ja, aber Sie können Ihrer Schnittstelle Getter und Setter hinzufügen, die die implementierenden Klassen dann implementieren müssen. Trotzdem erben die implementierenden Klassen keine Attribute. AFAICS ähnelt also eher einer Lösung im Trait-Stil als einer Lösung im Stil der Mehrfachvererbung.

OlliP
quelle
4

Kurz gesagt: Es handelt sich um einen Fehler bei der Kompilierung, der die Methode in der Implementierung manuell überschreiben muss.


Zweck der Standardmethode

Der Hauptzweck der Einführung der Standardmethode in Java 8 besteht darin, die Schnittstelle erweiterbar zu machen, ohne vorhandene Implementierungen zu beschädigen (es gibt so viele Java-Bibliotheken von Drittanbietern).

Und multiple inheritancewie in C ++ eigentlich vermieden werden soll, ist das definitiv nicht der Zweck der Standardmethode in Java.


So überschreiben Sie

2 Optionen:

  • Überschreiben Sie die Methode mit ihrer eigenen Logik.
  • Überschreiben Sie die Methode und rufen Sie eine der Methoden der Schnittstelle über das folgende superFormat auf:<interface_name>.super.<method_name>();

Tipps:

  • Die Methode von der Schnittstelle ist standardmäßig öffentlich. Vergessen Sie also nicht, publicbeim Überschreiben ein Schlüsselwort hinzuzufügen .
Eric Wang
quelle
2

Wenn noch jemand nach einer Antwort sucht und eine Klasse zwei Schnittstellen mit derselben Standardmethode implementiert, muss die Klasse die Eindeutigkeit auflösen, indem sie eine eigene Implementierung bereitstellt. In diesem Lernprogramm finden Sie weitere Informationen zur Funktionsweise der Vererbung in Standardmethoden.

Mithil-Studienwege
quelle
0

"Wie werden wir die Methoden unterscheiden?" War eine Frage, die auf Stackoverflow gestellt wurde und auf diese Frage konkrete Methoden in Schnittstellen Java1.8 verwies

Das folgende Beispiel sollte diese Frage beantworten:

interface A{
default public void m(){
System.out.println("Interface A: m()");
}
}

interface B{
default public void m(){
System.out.println("Interface B: m()");
}
}

 class C implements A,B { 

 public void m(){
  System.out.println("Concrete C: m()");   
 }

public static void main(String[] args) {
   C aC = new C();
   aC.m();
   new A(){}.m();
   new B(){}.m();
}
}

Die obige Klasse C muss eine eigene konkrete Methode für die Schnittstellen A und B implementieren.

 public void m(){
  System.out.println("Interface C: m()");   
 }

Um eine konkrete Implementierung einer Methode von einer bestimmten Schnittstelle aus aufzurufen , können Sie die Schnittstelle instanziieren und die konkrete Methode dieser Schnittstelle explizit aufrufen

Der folgende Code ruft beispielsweise die konkrete Implementierung der Methode m () von der Schnittstelle A auf :

new A(){}.m();

Die Ausgabe der oben genannten wäre:

Schnittstelle A: m ()

Mark Burleigh
quelle
-1

Meines Erachtens handelt es sich nicht um Mehrfachvererbung, da sie zustandslos sind. Virtuelle Erweiterungsmethoden unterstützen daher nicht die vollständige Objekt- oder Klassenfunktionalität.

Peter
quelle