Was ist die "Standard" -Implementierung einer in einer Schnittstelle definierten Methode?

91

In der Sammlungsschnittstelle habe ich eine Methode mit dem Namen gefunden removeIf(), die ihre Implementierung enthält.

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

Ich möchte wissen, ob es eine Möglichkeit gibt, den Methodenkörper in einer Schnittstelle zu definieren.
Was ist das defaultSchlüsselwort und wie funktioniert es?

gifpif
quelle
3
Siehe diesen Beitrag über die Standardeinstellung zeroturnaround.com/rebellabs/java-8-explained-default-methods/…
emeraldjava
In Verbindung stehender Beitrag stackoverflow.com/questions/31578427/…
Ravi

Antworten:

162

Von https://dzone.com/articles/interface-default-methods-java

Java 8 führt die neue Funktion "Standardmethode" oder (Verteidigungsmethoden) ein, mit der Entwickler den Schnittstellen neue Methoden hinzufügen können, ohne die vorhandene Implementierung dieser Schnittstelle zu beeinträchtigen. Es bietet Flexibilität, um die Implementierung einer Schnittstellendefinition zu ermöglichen, die standardmäßig verwendet wird, wenn eine konkrete Klasse keine Implementierung für diese Methode bereitstellt.

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

Es gibt eine häufig gestellte Frage zu Standardmethoden, wenn sie zum ersten Mal von der neuen Funktion erfahren:

Was ist, wenn die Klasse zwei Schnittstellen implementiert und beide Schnittstellen eine Standardmethode mit derselben Signatur definieren?

Beispiel zur Veranschaulichung dieser Situation:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

Dieser Code kann nicht mit folgendem Ergebnis kompiliert werden:

java: class Clazz inherits unrelated defaults for foo() from types A and B

Um dies zu beheben, müssen wir es in Clazz manuell beheben, indem wir die widersprüchliche Methode überschreiben:

public class Clazz implements A, B {
    public void foo(){}
}

Was aber, wenn wir die Standardimplementierung der Methode foo () von Schnittstelle A aus aufrufen möchten, anstatt unsere eigene zu implementieren?

Es ist möglich, auf A # foo () wie folgt zu verweisen:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}
gifpif
quelle
18
Danke, wirklich gute Ausstellung. Sie haben alle meine Fragen beantwortet, bevor ich sie stellen konnte.
Jeff Hutchins
Warum nicht stattdessen abstrakt verwenden?
Astolfo Hoscher
1
@AstolfoHoscher Sie können nur eine Klasse erweitern, aber Sie können mehrere Schnittstellen implementieren.
Charles Wood
49

Diese Methoden werden als Standardmethoden bezeichnet. Die Standardmethode oder Defender-Methode ist eine der neu hinzugefügten Funktionen in Java 8.

Sie werden verwendet, damit eine Schnittstellenmethode eine Implementierung bereitstellen kann, die standardmäßig verwendet wird, falls eine konkrete Klasse keine Implementierung für diese Methode bereitstellt.

Wenn Sie also eine Schnittstelle mit einer Standardmethode haben:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

Die folgende Klasse ist vollkommen gültig:

public class HelloImpl implements Hello {

}

Wenn Sie eine Instanz erstellen von HelloImpl:

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

Nützliche Links:

Rohit Jain
quelle
Ist es also in Ordnung, wenn eine Klasse eine Schnittstelle implementiert und ihre Methode nicht implementiert? Für Java7, das ich benutze, ist dies nicht erlaubt.
Aniket Thakur
2
@ AniketThakur. Dies ist vor Java 8 nicht zulässig. Diese Funktion wird nur in Java 8 hinzugefügt. Sie können vermeiden, Standardmethoden in Ihrer Implementierungsklasse zu implementieren.
Rohit Jain
1
@ PawanMishra. Siehe meinen vorherigen Kommentar. Nein, Sie müssen keine Standardschnittstellenmethoden für die Implementierung der Klasse implementieren.
Rohit Jain
1
@PawanMishra Sie können es jedoch überschreiben. Es gibt keine Einschränkung, da Sie nur die Standardimplementierung verwenden müssen.
Aniket Thakur
4
Ein Schritt nach vorne, der es endlich vermeidet, durch Mehrfachvererbung verwirrt zu werden!
Xtreme Biker
17

Ich habe ein bisschen recherchiert und Folgendes gefunden. Hoffe das hilft.

Bestehendes Problem

Normale Schnittstellenmethoden werden als abstrakt deklariert und müssen in der Klasse definiert werden, die die Schnittstelle implementiert. Dies "belastet" den Klassenimplementierer mit der Verantwortung, jede deklarierte Methode zu implementieren. Noch wichtiger ist, dass eine Erweiterung einer Schnittstelle nach der Veröffentlichung nicht möglich ist. Andernfalls müssten alle Implementierer ihre Implementierung anpassen, wodurch die Abwärtsquellen- und Binärkompatibilität unterbrochen wird.

Lösung in Java 8 übernommen

Um diese Probleme zu lösen, ist eine der neuen Funktionen von JDK 8 die Möglichkeit, vorhandene Schnittstellen mit Standardmethoden zu erweitern. Standardmethoden werden nicht nur deklariert, sondern auch in der Schnittstelle definiert.

Wichtige Punkte zu beachten

  1. Implementierer können festlegen, dass Standardmethoden in der implementierenden Klasse nicht implementiert werden.
  2. Implementierer können weiterhin Standardmethoden überschreiben, wie reguläre nicht endgültige Klassenmethoden in Unterklassen überschrieben werden können.
  3. Abstrakte Klassen können sogar Standardmethoden als abstrakt deklarieren, wodurch Unterklassen gezwungen werden, die Methode erneut zu implementieren (manchmal als "Neuabstraktion" bezeichnet).
Aniket Thakur
quelle