2014-09-11 13 views
7

Ich schaue zu Java 8 Nachrichten im Vergleich zu 7 und zusätzlich zu sehr interessanten Dingen wie Lambdas oder dem neuen Zeitrahmen fand ich, dass ein neues Feature (?) Eingeführt wurde: Standardmethoden.Warum brauchen wir Standardmethoden in Java?

fand ich das folgende Beispiel in this article:

public interface Math { 

    int add(int a, int b); 

    default int multiply(int a, int b) { 
     return a * b; 
    } 
} 

Es scheint mir sehr seltsam. Der obige Code sieht wie eine abstract Klasse mit einer implementierten Methode aus. Warum also Standardmethoden in eine Schnittstelle einführen? Was ist der eigentliche Vorteil dieses Ansatzes?

Im gleichen Artikel ich diese explaination lesen:

Warum sollte man Methoden in Interfaces hinzufügen? Das liegt daran, dass Schnittstellen zu eng mit ihren Implementierungsklassen verbunden sind. es ist nicht möglich, eine Methode in der Schnittstelle hinzuzufügen, ohne die Implementierungsklasse zu unterbrechen. Nachdem Sie eine Methode in der Schnittstelle hinzugefügt haben, müssen alle implementierten Klassen den Methodenkörper dieser neuen Methode deklarieren.

Nun, das überzeugt mich überhaupt nicht. IMHO Ich glaube, dass, wenn eine Klasse implementiert eine Schnittstelle obviously Methoden Körper für jede Methode darin deklarieren muss. Dies ist sicherlich eine Einschränkung, aber es ist auch eine Bestätigung seiner "Natur" (wenn Sie verstehen, was ich meine ...)

Wenn Sie gemeinsame Logik zu jeder erbenden Klasse haben, werden Sie es in eine implementierende abstract Klasse .

Also, Was ist der wahre Vorteil einer Standardmethode? (Es sieht eher wie dieses Problem zu umgehen, als ein neues Feature ...)


UPDATE Ich verstehe, dass dieser Ansatz für die Abwärtskompatibilität ist, aber es hat mich noch nicht überzeugen so sehr. Eine Schnittstelle repräsentiert ein Verhalten, das eine Klasse MUSS haben muss. Eine Klasse, die eine bestimmte Schnittstelle implementiert, hat sicherlich dieses Verhalten. Aber wenn jemand die Schnittstelle beliebig ändern kann, ist diese Einschränkung gebrochen. Das Verhalten kann sich jederzeit ändern ... liege ich falsch?

+0

In Verbindung stehende: http://StackOverflow.com/Questions/19998454/interface-with-default-methods-VS-abstract-Class-in-Java-8 und http://StackOverflow.com/Questions/20139404/Java -8-default-methods-vs-non-abstract-Methoden-in-abstract-classes – assylias

+0

Sie können nur eine Klasse erweitern, aber beliebig viele Schnittstellen implementieren. –

Antwort

7

Dies ist für Abwärtskompatibilität.

Wenn Sie eine Schnittstelle haben, die andere Leute implementiert haben, dann wenn Sie eine neue Methode zur Schnittstelle hinzufügen, sind alle vorhandenen Implementierungen gebrochen.

Durch Hinzufügen einer neuen Methode mit einer Standardimplementierung bleiben Sie mit bestehenden Implementierungen quellkompatibel.

Für eine etwas simple/konstruiertes Beispiel, das hoffentlich zeigen, sollte dies sagen wir Ihnen eine Bibliothek erstellt:

void drawSomething(Skin skin) { 
} 

interface Skin { 
    Color getColor(); 
    Image getBackgroundImage(); 
} 

Jetzt haben Sie eine neue Version Ihrer Bibliothek zu tun kommen, und Sie wollen das Konzept hinzufügen von Grenzfarben ist so einfach an die Schnittstelle hinzuzufügen: sie je getan haben, und fügen sie diese neue Methode

interface Skin { 
    Color getColor(); 
    Color getBorderColor(); 
    Image getBackgroundImage(); 
} 

Aber das Problem ist, dass jede einzelne Person, die Ihre Bibliothek durch jede einzelne Haut Umsetzung gehen zurück.

Wenn Sie stattdessen eine Standardimplementierung zu getBorderColor, die nur getColor genannt wird, dann alles "funktioniert".

+0

ok, aber das Hinzufügen von Methode Körper innerhalb einer Schnittstelle klingt sehr seltsam für mich ... – davioooh

+1

@davioooh ist es seltsam, aber wenn Oracle konfrontiert mit Rückwärtskompatibilität in Java 8, wenn Lambda verbesserte Methoden zu den Sammlungen apis hinzufügen; Sie wählten diesen Ansatz als das kleinere Übel. –

+0

Auch dann gilt diese Rückwärtskompatibilität nur für eine Methode, was, falls wir eine andere Methode einführen müssen? – zerocool

0

Angenommen, Sie möchten neue Funktionalität in deklarierter Schnittstelle hinzufügen, bis zu Java 7, Wenn Sie eine neue Methode in einer Schnittstelle deklariert hinzufügen, müssen Sie auch die Implementierung der Methode in implementierenden Klassen definieren diese Schnittstelle.

In Java 8 können Sie eine Standardmethode hinzufügen, die die Implementierung enthält, und die gesamte untergeordnete Klasse erbt diese Methode.

Edit: (Nach Frage Update)

Eine Schnittstelle ein Verhalten dar, dass eine Klasse haben muss

Es ist immer noch ein Verhalten darstellen muss diese Klasse haben, Ihre Verwirrung ist, wie Sie definieren Verhalten. Alle Implementierungsklassen erben die Standardmethode und können auch ihre eigene Implementierung schreiben. Beachten Sie folgende Fälle:

  1. Wenn die implementierende Klasse keine eigene Implementierung bereitstellt und einfach die Standardmethode erbt. Wenn Sie das Verhalten der Standardmethode in der Schnittstelle ändern, haben implementierende Klassen ein aktuelles Verhalten, da sie die Standardmethode erben, so dass sie enthält. Eine Schnittstelle repräsentiert ein Verhalten, das eine Klasse haben muss.
  2. Wenn Implementierungsklasse eigene Version der Standardmethode bereitstellen, und wenn Sie das Verhalten (nur Argumente) der Standardmethode ändern. In diesem Fall verfügt die implementierende Klasse über zwei überladene Methoden, von denen eine zuvor definiert wurde und die zweite Standardmethode übernommen wird. Wenn Sie das vollständige Verhalten ändern (auch Argumente mit dem Rückgabetyp), entsteht eine Mehrdeutigkeit beim Implementieren der Klasse, da Sie die Methode nicht überladen können, indem Sie den Rückgabetyp ändern, und die Implementierung wird unterbrochen. wieder hält es Eine Schnittstelle repräsentieren ein Verhalten, das eine Klasse haben muss.

Beispiel:

Bulk-Datenoperation in der Sammlung hinzugefügt wird in Java 8 (Referenz: http://openjdk.java.net/jeps/107), zu implementieren, die in Verfahren forEach()Iterable Schnittstelle hinzugefügt wird. Das Hinzufügen der abstrakten Methode in der Schnittstelle Iterable würde den gesamten vorhandenen Code durchbrechen, da jede Klasse diese Methode implementieren muss.

das Problem Solving, folgende Standard forEach() Methode in Iterable Schnittstelle hinzugefügt wird,

interface Iterable 
{ 
    default void forEach(Consumer<? super T> action) 
    { 
     for (T t : this) action.accept(t); 
    } 
} 

Referenz: Java 8 : Default method in Interface

+0

Ihre Referenz ist ein bisschen veraltet. Was in sehr frühen Versionen "Block" genannt wurde, heißt seit einiger Zeit Consumer. Außerdem macht es keinen Sinn, (richtigerweise) zu sagen, dass 'forEach' zu 'Iterable' hinzugefügt wurde, aber Beispielcode geschrieben wird, der es anschließend in' Collection' definiert. Siehe http://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html#forEach-java.util.function.Consumer- – Holger

+0

@Holger Ich bekomme keinen Hinweis auf 'forEach' Kannst du bitte etwas erklären !! (nicht streiten, nehmen Sie dies als ein positives pls) –

+0

@Holger Ohh !!! hat die Antwort aktualisiert und wird auch den Artikel aktualisieren.Es wurde vor langer Zeit geschrieben (31. März 2014), übrigens danke :) –

3

Es gibt viele Methoden wurden auf eine abstrakte Schnittstelle in der Vergangenheit handeln. Vor Java 8 mussten sie in eine zusätzliche Klasse eingefügt werden, die die Schnittstelle paarte, z. Collections mit Collection.

Dieser alte Ansatz war nicht überzeugender als default Methoden noch praktischer. Anstelle list.sort() musste man Collections.sort(list) sagen. Dies bedeutet auch, dass Sie beim Erstellen eines interface eine grundlegende Entscheidung treffen mussten, entweder Sie benötigen jede List Implementierung, um eine sort-Methode zu implementieren, oder Sie stellen eine sort-Methode in einer Dienstprogrammklasse bereit, die nicht überschrieben werden kann.

Mit default Methoden, die Sie beide haben können, eine Standard-Implementierung, die die List Implementierungen müssen nicht auf seinem eigenen implementieren, kann aber immer noch außer Kraft gesetzt werden, wenn eine konkrete Umsetzung eine effizientere Art und Weise hat es zu tun, um seine Interna zu wissen, z.B. ArrayList.sort übergibt das interne Array direkt an Arrays.sort überspringt einige Zwischenoperationen.