Was ist der Zweck des Standardschlüsselworts in Java?


92

Eine Schnittstelle in Java ähnelt einer Klasse, der Hauptteil einer Schnittstelle kann jedoch nur abstrakte Methoden und finalFelder (Konstanten) enthalten.

Kürzlich habe ich eine Frage gesehen, die so aussieht

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

Gemäß der Schnittstellendefinition sind nur abstrakte Methoden zulässig. Warum kann ich den obigen Code kompilieren? Was ist das defaultSchlüsselwort?

Auf der anderen Seite, wenn ich versucht habe, unten Code zu schreiben, dann heißt es modifier default not allowed here

default class MyClass{

}

anstatt

class MyClass {

}

Kann mir jemand den Zweck des defaultSchlüsselworts sagen ? Ist es nur innerhalb einer Schnittstelle erlaubt? Wie unterscheidet es sich von default(kein Zugriffsmodifikator)?


4
Standardmethoden in Schnittstellen wurden in Java 8 hinzugefügt. Es handelt sich nicht um einen Zugriffsmodifikator, sondern um eine Standardimplementierung.
Eran

2
@Eran, denkst du nicht, Einführung einer Standardmethode, die gegen die Schnittstellendefinition verstößt? : s
Ravi

2
Es hat die Schnittstellendefinition geändert. Diese Definition ist jetzt veraltet.
Louis Wasserman

2
Sie wurden eingeführt, um Lambdas zu unterstützen. Die Einzelheiten, warum sie benötigt werden, sind im Strohmann-Vorschlag für das Projekt Lambda enthalten.
Sprinter

Antworten:


71

Es ist eine neue Funktion in Java 8 interface, mit der eine Implementierung bereitgestellt werden kann. Beschrieben in Java 8 JLS-13.5.6. Schnittstellenmethodendeklarationen, die (teilweise) lauten

Das Hinzufügen einer defaultMethode oder das Ändern einer Methode von abstractnach defaultunterbricht nicht die Kompatibilität mit bereits vorhandenen Binärdateien, kann jedoch dazu führen, IncompatibleClassChangeErrordass eine bereits vorhandene Binärdatei versucht, die Methode aufzurufen. Dieser Fehler tritt auf, wenn die Qualifikation Typ T, ein Subtyp von zwei Schnittstellen ist, Iund J, wo beide Iund Jdeklarieren Sie eine defaultMethode mit der gleichen Signatur und Ergebnis, und weder Inoch Jist ein Subschnittstelle des anderen.

Was ist neu in JDK 8 sagt (teilweise)

Standardmethoden ermöglichen das Hinzufügen neuer Funktionen zu den Schnittstellen von Bibliotheken und stellen die Binärkompatibilität mit Code sicher, der für ältere Versionen dieser Schnittstellen geschrieben wurde.


16
Es scheint, dass jetzt Schnittstelle und abstrakte Klasse fast gleich sind. :)
Ravi

15
@ jWeaver-Schnittstellen können weiterhin keine Konstruktoren, Felder, privaten Methoden oder Implementierungen von equals / hashCode / toString enthalten.
Louis Wasserman

10
@ Louis Wasserman: In Java 9 können sie privateMethoden haben.
Holger

6
@ Dan Pantry: privateMethoden sind nicht wirklich Teil der Schnittstelle, können aber als Hilfsmethoden für die defaultImplementierungen oder innerhalb konstanter Initialisierer dienen. Beachten Sie, dass sie bereits in Java 8 vorhanden sind, da bei Verwendung von Lambda-Ausdrücken in Schnittstellen synthetische privateMethoden generiert werden. Mit Java 9 können Sie diese Funktion also auch für nicht synthetische und nicht Lambda-Anwendungen verwenden.
Holger

14
@jWeaver Der Unterschied zwischen Schnittstellen und Klassen reduziert sich auf Status und Verhalten . Schnittstellen können Verhalten tragen, aber nur Klassen können Status haben. (Felder, Konstruktoren und Methoden wie equals / hashCode handeln vom Status.)
Brian Goetz

26

Java 8 wurden hauptsächlich Standardmethoden hinzugefügt, um Lambda-Ausdrücke zu unterstützen. Die Designer (meiner Ansicht nach klug) haben beschlossen, Lambdas-Syntax für die Erstellung anonymer Implementierungen einer Schnittstelle zu erstellen. Da gegebene Lambdas jedoch nur eine einzige Methode implementieren können, wären sie auf Schnittstellen mit einer einzigen Methode beschränkt, was eine ziemlich strenge Einschränkung darstellen würde. Stattdessen wurden Standardmethoden hinzugefügt, um die Verwendung komplexerer Schnittstellen zu ermöglichen.

Wenn Sie die Behauptung, defaultdie aufgrund von Lambdas eingeführt wurde, überzeugen möchten, beachten Sie, dass im Strohmann-Vorschlag des Projekts Lambda von Mark Reinhold aus dem Jahr 2009 „Erweiterungsmethoden“ als obligatorische Funktion zur Unterstützung von Lambdas erwähnt werden.

Hier ist ein Beispiel, das das Konzept demonstriert:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

Sehr konstruiert ist mir klar, aber ich sollte veranschaulichen, wie defaultLambdas unterstützt werden. Da dies inverseeine Standardeinstellung ist, kann sie bei Bedarf leicht von einer implementierenden Klasse überschrieben werden.


8
Das ist nicht wirklich richtig. Lambdas mögen die unmittelbare Ursache sein, aber sie waren wirklich nur der Strohhalm, der dem Kamel den Rücken gebrochen hat. Die eigentliche Motivation bestand darin, die Entwicklung von Schnittstellen zu ermöglichen (vorhandene Kompatibilitäten können kompatibel weiterentwickelt werden, um neues Verhalten zu unterstützen). Lambdas waren vielleicht der Faktor, der dieses Bedürfnis in den Vordergrund gerückt hat, aber das Merkmal ist allgemeiner.
Brian Goetz

@BrianGoetz: IMHO hätten sowohl Java als auch .NET enorm davon profitiert, wenn von Anfang an Standardmethoden vorhanden gewesen wären. Wenn eine allgemeine Operation für eine Implementierung einer Schnittstelle ausgeführt werden könnte, bei der nur Schnittstellenelemente verwendet werden, einige Implementierungen jedoch wahrscheinlich effizienter sind, sollte die Schnittstelle Methoden für diese Operationen definieren und Standardimplementierungen für sie bereitstellen. Die Unfähigkeit, Standardimplementierungen anzugeben, hat zu dem Druck geführt, dass Schnittstellen solche Methoden weglassen, und es ihnen unmöglich gemacht, sie später hinzuzufügen.
Supercat

@BrianGoetz Ich bin damit einverstanden, dass Standardmethoden über Lambdas hinaus einen signifikanten Wert haben. Aber ich würde mich für jeden Hinweis interessieren, den Sie auf diesen breiteren Wert geben können, der die Entscheidung antreibt, sie aufzunehmen. Ich lese, dass Lambdas der Hauptgrund waren (weshalb ich in meiner Antwort das Wort "hauptsächlich" verwendet habe).
Sprinter

2
Vielleicht hilft dieses Dokument: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . In Abschnitt 10 heißt es klar: "Der Zweck von Standardmethoden (früher als virtuelle Erweiterungsmethoden oder Verteidigermethoden bezeichnet) besteht darin, die Entwicklung von Schnittstellen nach ihrer Erstveröffentlichung auf kompatible Weise zu ermöglichen." Lambda-freundliche Methoden werden dann zur Veranschaulichung der Schnittstellenentwicklung angeführt .
Brian Goetz

2
@ Kartik Du stellst die falsche Frage! Wir wählen die Syntax nicht basierend auf "Was ist das absolute Minimum, das der Compiler benötigt, um das Programm korrekt zu analysieren?". Wir wählen es auf der Grundlage von "was die Absicht des Programmierers für die Leser sofort deutlicher machen würde". Wir entwerfen zuerst für Benutzer und zweitens für Compiler (und wenn es um Benutzer geht, entwerfen wir zuerst zum Lesen und zweitens zum Schreiben.)
Brian Goetz

15

In Java 8 wird ein neues Konzept eingeführt, das als Standardmethoden bezeichnet wird. Standardmethoden sind Methoden mit einer Standardimplementierung, die bei der Weiterentwicklung der Schnittstellen helfen, ohne den vorhandenen Code zu beschädigen. Schauen wir uns ein Beispiel an:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

und die Ausgabe ist:

Do Some Work-Implementierung in der Klasse
DoSomeOtherWork-Implementierung in der Schnittstelle


15

Was in den anderen Antworten übersehen wurde, war seine Rolle in Anmerkungen. Bereits in Java 1.5 wurde das defaultSchlüsselwort verwendet, um einen Standardwert für ein Anmerkungsfeld bereitzustellen .

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Die Verwendung wurde mit der Einführung von Java 8 überlastet , damit eine Standardmethode in Schnittstellen definiert werden kann.

Etwas anderes, das übersehen wurde: Der Grund, warum die Deklaration default class MyClass {}ungültig ist, liegt in der Art und Weise, wie Klassen überhaupt deklariert werden . Es gibt keine Bestimmung in der Sprache, die es erlaubt, dass dieses Schlüsselwort dort angezeigt wird. Es wird jedoch für Deklarationen von Schnittstellenmethoden angezeigt.


3

Mit der neuen Java 8- Funktion ( Standardmethoden ) kann eine Schnittstelle eine Implementierung bereitstellen, wenn sie mit dem defaultSchlüsselwort gekennzeichnet ist.

Beispielsweise:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Der Schnittstellentest verwendet das Standardschlüsselwort, mit dem die Schnittstelle eine Standardimplementierung der Methode bereitstellen kann, ohne dass diese Methoden in den Klassen implementiert werden müssen, die die Schnittstelle verwenden.

Abwärtskompatibilität: Stellen Sie sich vor, Ihre Schnittstelle wird von Hunderten von Klassen implementiert. Wenn Sie diese Schnittstelle ändern, werden alle Benutzer gezwungen, die neu hinzugefügte Methode zu implementieren, obwohl dies für viele andere Klassen, die Ihre Schnittstelle implementieren, nicht unbedingt erforderlich ist.

Fakten & Einschränkungen:

1-Darf nur innerhalb einer Schnittstelle und nicht innerhalb einer Klasse oder abstrakten Klasse deklariert werden.

2-Muss einen Körper bereitstellen

3-Es wird nicht davon ausgegangen, dass es öffentlich oder abstrakt ist wie andere normale Methoden, die in einer Schnittstelle verwendet werden.


2

Eine sehr gute Erklärung finden Sie in den Java ™ -Tutorials . Ein Teil der Erklärung lautet wie folgt:

Stellen Sie sich ein Beispiel vor, an dem Hersteller von computergesteuerten Autos beteiligt sind, die Schnittstellen nach Industriestandard veröffentlichen, die beschreiben, welche Methoden zum Betrieb ihrer Autos aufgerufen werden können. Was ist, wenn diese computergesteuerten Autohersteller ihren Autos neue Funktionen wie den Flug hinzufügen? Diese Hersteller müssten neue Methoden festlegen, damit andere Unternehmen (z. B. Hersteller elektronischer Leitinstrumente) ihre Software an fliegende Autos anpassen können. Wo würden diese Autohersteller diese neuen flugbezogenen Methoden deklarieren? Wenn sie sie zu ihren ursprünglichen Schnittstellen hinzufügen, müssten Programmierer, die diese Schnittstellen implementiert haben, ihre Implementierungen neu schreiben. Wenn sie sie als statische Methoden hinzufügen, würden Programmierer sie als Dienstprogrammmethoden betrachten, nicht als wesentliche Kernmethoden.

Mit Standardmethoden können Sie den Schnittstellen Ihrer Bibliotheken neue Funktionen hinzufügen und die Binärkompatibilität mit Code sicherstellen, der für ältere Versionen dieser Schnittstellen geschrieben wurde.


2

Standardmethoden in einer Schnittstelle ermöglichen es uns, neue Funktionen hinzuzufügen, ohne alten Code zu beschädigen.

Wenn vor Java 8 einer Schnittstelle eine neue Methode hinzugefügt wurde, mussten alle Implementierungsklassen dieser Schnittstelle diese neue Methode überschreiben, auch wenn sie die neue Funktionalität nicht verwendeten.

Mit Java 8 können wir die Standardimplementierung für die neue Methode hinzufügen, indem wir das defaultSchlüsselwort vor der Methodenimplementierung verwenden.

Selbst bei anonymen Klassen oder funktionalen Schnittstellen können wir Standardimplementierungen dieser Codes schreiben und sie wiederverwenden, wenn wir feststellen, dass ein Teil des Codes wiederverwendbar ist und wir nicht überall im Code dieselbe Logik definieren möchten.

Beispiel

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

1

Mit Standardmethoden können Sie den Schnittstellen Ihrer Apps neue Funktionen hinzufügen. Es kann auch für eine Mehrfachvererbung verwendet werden . Zusätzlich zu den Standardmethoden können Sie statische Methoden in Schnittstellen definieren. Dies erleichtert Ihnen das Organisieren von Hilfsmethoden

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.