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.

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

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 {}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow