Java Language
Standardmethoden
Suche…
Einführung
Mit der in Java 8 eingeführten Standardmethode können Entwickler einer Schnittstelle neue Methoden hinzufügen, ohne die vorhandenen Implementierungen dieser Schnittstelle zu beschädigen. Es bietet Flexibilität, damit die Schnittstelle eine Implementierung definieren kann, die standardmäßig verwendet wird, wenn eine Klasse, die diese Schnittstelle implementiert, keine Implementierung dieser Methode bereitstellt.
Syntax
- public default void methodName () {/ * Methodenkörper * /}
Bemerkungen
Standardmethoden
- Kann innerhalb einer Schnittstelle verwendet werden, um ein Verhalten einzuführen, ohne vorhandene Unterklassen zur Implementierung zu zwingen.
- Kann von Unterklassen oder von einem Subinterface überschrieben werden.
- In der Klasse java.lang.Object dürfen keine Methoden überschrieben werden.
- Wenn eine Klasse, die mehr als eine Schnittstelle implementiert, Standardmethoden mit identischen Methodensignaturen von den einzelnen Schnittstellen erbt, muss sie ihre eigene Schnittstelle überschreiben und so angeben, als wären sie keine Standardmethoden (als Teil der Auflösung der Mehrfachvererbung).
- Obwohl beabsichtigt wird, ein Verhalten einzuführen, ohne vorhandene Implementierungen zu unterbrechen, werden vorhandene Unterklassen mit einer statischen Methode mit derselben Methodensignatur wie die neu eingeführte Standardmethode weiterhin beschädigt. Dies gilt jedoch auch für die Einführung einer Instanzmethode in einer Superklasse.
Statische Methoden
- Kann innerhalb einer Schnittstelle verwendet werden, die hauptsächlich als Hilfsmittel für Standardmethoden verwendet werden soll.
- Kann nicht von Unterklassen oder von einem Subinterface überschrieben werden (ist für sie ausgeblendet). Wie schon bei statischen Methoden kann jedoch auch jede Klasse oder jedes Interface eine eigene haben.
- Es ist nicht zulässig, Instanzmethoden in der Klasse java.lang.Object zu überschreiben (wie dies auch für Unterklassen der Fall ist).
Die folgende Tabelle fasst die Interaktion zwischen Unterklasse und Oberklasse zusammen.
- | SUPER_CLASS-INSTANZ-METHODE | SUPER_CLASS-STATIC-METHODE |
---|---|---|
SUB_CLASS-INSTANCE-METHODE | überschreibt | generiert-compiletime-error |
SUB_CLASS-STATIC-METHODE | generiert-compiletime-error | versteckt sich |
Nachfolgend finden Sie eine Tabelle, die die Interaktion zwischen Schnittstelle und Implementierungsklasse zusammenfasst.
- | INTERFACE-DEFAULT-METHODE | SCHNITTSTELLE-STATISCHE-METHODE |
---|---|---|
IMPL_CLASS-INSTANCE-METHODE | überschreibt | versteckt sich |
IMPL_CLASS-STATIC-METHODE | generiert-compiletime-error | versteckt sich |
Verweise :
- http://www.journaldev.com/2752/java-8-interface-changes-static-method-default-method
- https://docs.oracle.com/javase/tutorial/java/IandI/override.html
Grundlegende Verwendung von Standardmethoden
/**
* Interface with default method
*/
public interface Printable {
default void printString() {
System.out.println( "default implementation" );
}
}
/**
* Class which falls back to default implementation of {@link #printString()}
*/
public class WithDefault
implements Printable
{
}
/**
* Custom implementation of {@link #printString()}
*/
public class OverrideDefault
implements Printable {
@Override
public void printString() {
System.out.println( "overridden implementation" );
}
}
Die folgenden aussagen
new WithDefault().printString();
new OverrideDefault().printString();
Erzeugt diese Ausgabe:
default implementation
overridden implementation
Zugriff auf andere Schnittstellenmethoden innerhalb der Standardmethode
Sie können auch auf andere Schnittstellenmethoden innerhalb Ihrer Standardmethode zugreifen.
public interface Summable {
int getA();
int getB();
default int calculateSum() {
return getA() + getB();
}
}
public class Sum implements Summable {
@Override
public int getA() {
return 1;
}
@Override
public int getB() {
return 2;
}
}
Die folgende Anweisung wird 3 drucken:
System.out.println(new Sum().calculateSum());
Standardmethoden können auch zusammen mit statischen Methoden der Schnittstelle verwendet werden:
public interface Summable {
static int getA() {
return 1;
}
static int getB() {
return 2;
}
default int calculateSum() {
return getA() + getB();
}
}
public class Sum implements Summable {}
Die folgende Anweisung wird auch 3 drucken:
System.out.println(new Sum().calculateSum());
Zugriff auf überschriebene Standardmethoden aus der implementierenden Klasse
In Klassen wird super.foo()
nur in Superklassen super.foo()
. Wenn Sie eine Standardimplementierung von einem Superinterface aus aufrufen möchten, müssen Sie sich super
mit dem Namen der Schnittstelle qualifizieren: Fooable.super.foo()
.
public interface Fooable {
default int foo() {return 3;}
}
public class A extends Object implements Fooable {
@Override
public int foo() {
//return super.foo() + 1; //error: no method foo() in java.lang.Object
return Fooable.super.foo() + 1; //okay, returns 4
}
}
Warum Standardmethoden verwenden?
Die einfache Antwort ist, dass Sie eine vorhandene Schnittstelle weiterentwickeln können, ohne vorhandene Implementierungen zu beschädigen.
Zum Beispiel haben Sie eine Swim
, die Sie vor 20 Jahren veröffentlicht haben.
public interface Swim {
void backStroke();
}
Wir haben großartige Arbeit geleistet, unsere Benutzeroberfläche ist sehr beliebt, es gibt viele Implementierungen auf der ganzen Welt und Sie haben keine Kontrolle über den Quellcode.
public class FooSwimmer implements Swim {
public void backStroke() {
System.out.println("Do backstroke");
}
}
Nach 20 Jahren haben Sie sich entschieden, der Benutzeroberfläche neue Funktionen hinzuzufügen. Es sieht jedoch so aus, als ob unsere Benutzeroberfläche eingefroren ist, da bestehende Implementierungen dadurch beschädigt werden.
Glücklicherweise führt Java 8 eine brandneue Funktion namens Default-Methode ein.
Wir können jetzt der Swim
Oberfläche eine neue Methode hinzufügen.
public interface Swim {
void backStroke();
default void sideStroke() {
System.out.println("Default sidestroke implementation. Can be overridden");
}
}
Jetzt können alle vorhandenen Implementierungen unserer Schnittstelle weiterhin funktionieren. Am wichtigsten ist jedoch, dass sie die neu hinzugefügte Methode zu ihrer eigenen Zeit implementieren können.
Einer der Hauptgründe für diese Änderung und eine ihrer größten Anwendungen liegt im Java Collections-Framework. Oracle konnte der vorhandenen Iterable-Schnittstelle keine foreach
Methode hinzufügen, ohne den gesamten vorhandenen Code zu zerstören, der Iterable implementiert hat. Durch das Hinzufügen von Standardmethoden erbt die vorhandene Iterable-Implementierung die Standardimplementierung.
Klasse, abstrakte Klasse und Schnittstellenmethode Vorrang
Implementierungen in Klassen, einschließlich abstrakter Deklarationen, haben Vorrang vor allen Schnittstellenstandardwerten.
- Die abstrakte Klassenmethode hat Vorrang vor der Schnittstellenstandardmethode .
public interface Swim {
default void backStroke() {
System.out.println("Swim.backStroke");
}
}
public abstract class AbstractSwimmer implements Swim {
public void backStroke() {
System.out.println("AbstractSwimmer.backStroke");
}
}
public class FooSwimmer extends AbstractSwimmer {
}
Die folgende Aussage
new FooSwimmer().backStroke();
Wird herstellen
AbstractSwimmer.backStroke
- Klassenmethode hat Vorrang vor Schnittstellenstandardmethode
public interface Swim {
default void backStroke() {
System.out.println("Swim.backStroke");
}
}
public abstract class AbstractSwimmer implements Swim {
}
public class FooSwimmer extends AbstractSwimmer {
public void backStroke() {
System.out.println("FooSwimmer.backStroke");
}
}
Die folgende Aussage
new FooSwimmer().backStroke();
Wird herstellen
FooSwimmer.backStroke
Standardmethode Mehrfachvererbungskollision
Betrachten Sie das nächste Beispiel:
public interface A {
default void foo() { System.out.println("A.foo"); }
}
public interface B {
default void foo() { System.out.println("B.foo"); }
}
Hier sind zwei Schnittstellen, die die default
foo
mit derselben Signatur deklarieren.
Wenn Sie versuchen extend
diese beiden Schnittstellen in der neuen Schnittstelle zu erweitern, müssen Sie zwei auswählen, da Java Sie zwingt, diese Kollision explizit aufzulösen.
Zunächst können Sie die Methode foo
mit derselben Signatur wie abstract
deklarieren, wodurch das Verhalten von A
und B
außer Kraft gesetzt wird.
public interface ABExtendsAbstract extends A, B {
@Override
void foo();
}
Und wenn Sie ABExtendsAbstract
in der class
implement
ABExtendsAbstract
Sie eine foo
Implementierung bereitstellen:
public class ABExtendsAbstractImpl implements ABExtendsAbstract {
@Override
public void foo() { System.out.println("ABImpl.foo"); }
}
Oder zweitens, können Sie eine völlig neue schaffen default
Sie können den Code der A
und B
foo
Methoden auch wiederverwenden, indem Sie von der Implementierung der Klasse auf überschriebene Standardmethoden zugreifen .
public interface ABExtends extends A, B {
@Override
default void foo() { System.out.println("ABExtends.foo"); }
}
Und wenn Sie ABExtends
in der class
implement
ABExtends
Sie not
foo
Implementierung bereitstellen:
public class ABExtendsImpl implements ABExtends {}