Die Standardmethode fügt dem Anweisungssatz des JVM eine sehr gute neue Funktion hinzu. Nach Verwendung der Standardmethode kann die Benutzerklasse, die diese Schnittstelle implementiert, die Standardimplementierung dieser Methode automatisch abrufen, wenn eine neue Methode hinzugefügt wird. Sobald der Benutzer seine Implementierungsklasse aktualisieren möchte, überschreiben Sie einfach diese Standardmethode und ersetzen Sie sie durch eine Implementierung, die in einem bestimmten Szenario aussagekräftiger wird. Noch besser ist, dass Benutzer die Standardimplementierung der Schnittstelle in der umgeschriebenen Methode aufrufen können, um einige zusätzliche Funktionen hinzuzufügen.
Bisher ist alles ziemlich gut. Das Hinzufügen von Standardmethoden zu vorhandenen Java -Schnittstellen kann jedoch zu Codekompatibilität führen . Es ist leicht zu verstehen, wenn Sie sich ein Beispiel ansehen. Angenommen, es gibt eine Bibliothek, in der der Benutzer eine seiner Schnittstellen als Eingabe implementieren muss:
Schnittstelle SimpleInput {void foo (); void bar ();} Abstract Class SimpleInputAdapter implementiert SimpleInput {@Override public void bar () {// ein Standardverhalten ...}}Vor Java 8 war die Kombination der obigen Schnittstelle und einer entsprechenden Adapterklasse ein sehr häufiges Muster in der Java -Sprache. Die Entwickler der Klassenbibliothek stellen einen Adapter zur Reduzierung der Codierung der Bibliotheksverbraucher an. Der Zweck dieser Schnittstelle besteht jedoch darin, eine Beziehung zu erreichen, die der multiplen Vererbung ähnelt.
Nehmen wir an, dass ein Benutzer diesen Adapter verwendet:
Klasse myInput erweitert SimpleInputAdapter {@Override public void foo () {// etwas tun ...} @Override public void bar () {Super.bar (); // etwas zusätzlich machen ...}}Mit dieser Implementierung können Benutzer mit der Bibliothek interagieren. Beachten Sie, wie diese Implementierung die Balkenmethode überschreibt, um der Standardimplementierung zusätzliche Funktionen hinzuzufügen.
Was würde also passieren, wenn diese Bibliothek in Java 8 migriert würde? Zunächst wird diese Bibliothek die Adapterklasse wahrscheinlich verwerfen und diese Funktion auf die Standardmethode migrieren. Am Ende sieht diese Schnittstelle wie folgt aus:
Schnittstelle SimpleInput {void foo (); Standard void bar () {// ein Standardverhalten}}}Mit dieser neuen Schnittstelle muss der Benutzer seinen Code aktualisieren, um diese Standardmethode anstelle der Adapterklasse zu verwenden. Einer der großen Vorteile der Verwendung einer neuen Schnittstelle anstelle einer Adapterklasse besteht darin, dass Benutzer eine andere Klasse anstelle dieser Adapterklasse erben können. Beginnen wir mit der MyInput -Klasse in die Standardmethode. Da wir jetzt andere Klassen erben können, werden wir versuchen, eine zusätzliche Basisklasse von Drittanbietern zu erweitern. Was diese Basisklasse tut, ist hier nicht wichtig. Nehmen wir an, dass dies für unseren Anwendungsfall sinnvoll ist.
Klasse myInput erweitert DrittelPartyBaseClass implementiert SimpleInput {@Override public void foo () {// etwas tun ...} @Override public void bar () {SimpleInput.super.foo (); // etwas zusätzlich machen ...}}Um dieselbe Funktion wie die ursprüngliche Klasse zu erreichen, haben wir die neue Java 8 -Syntax verwendet, um die Standardmethoden der Schnittstelle aufzurufen. In ähnlicher Weise setzen wir die Logik von MyMethod in eine Basisklasse -MyBase ein. Sie können sich entspannen, nachdem Sie Ihre Schultern geschlagen haben. Nach dem Refactoring war es großartig!
Diese Bibliothek, die wir verwenden, wurde stark verbessert. Wartungspersonal muss jedoch eine weitere Schnittstelle hinzufügen, um zusätzliche Funktionen zu implementieren. Diese Schnittstelle wird als Compexinput bezeichnet, das die SimpleInput -Klasse erbt und eine zusätzliche Methode hinzufügt. Da allgemein angenommen wird, dass die Standardmethode mit Vertrauen hinzugefügt werden kann, hat das Wartungspersonal die Standardmethode der SimpleInput -Klasse überschrieben und einige zusätzliche Aktionen hinzugefügt, um dem Benutzer eine bessere Standardimplementierung zu bieten. Immerhin ist dies bei Verwendung von Adapterklassen sehr häufig:
Interface ComplexInput erweitert SimpleInput {void qux (); @Override Standard void bar () {simpleInput.super.bar (); // so komplex, dass wir mehr tun müssen ...}}Diese neue Funktion sieht sehr gut aus, sodass der Betreuer der Drittel -Partybaseclass -Klasse auch beschlossen hat, diese Bibliothek zu verwenden. Um dies zu erreichen, implementierte er die DrittPartyBaseClass -Klasse in die Komplexinput -Schnittstelle.
Aber was bedeutet das für die MyInput -Klasse? Da es die DrittPartyBaseClass -Klasse erbt, wird die KomplexInput -Schnittstelle standardmäßig implementiert. Auf diese Weise ist es nicht legal, die Standardmethode von SimpleInput zu bezeichnen. Das Ergebnis ist, dass der Code des Benutzers am Ende nicht kompiliert werden kann. Außerdem ist diese Methode völlig unmöglich anzurufen, da Java diese Super-Super-Methode für die indirekte Elternklasse als illegal bezeichnet. Sie können nur die Standardmethode der KomplexInput -Schnittstelle aufrufen. Dies erfordert jedoch zunächst, dass Sie diese Schnittstelle explizit in der MyInput -Klasse implementieren. Für Benutzer dieser Bibliothek sind diese Änderungen völlig unerwartet.
(Hinweis: Um es einfach auszudrücken, ist es tatsächlich:
Schnittstelle A {Standard void test () {}} Schnittstelle B erweitert einen {Standard -void test () {}} öffentliche Klassen -Test implementiert b {public void test () {b.super.test (); //A.super.test (); Fehler }}Wenn Sie dies schreiben, hat sich der Benutzer natürlich aktiv für die Implementierung der B -Schnittstelle entschieden. Das Beispiel in dem Artikel führte eine Basisklasse ein, sodass in der Bibliothek und der Basisklasse eine scheinbar unblutgierige Änderung vorgenommen wurde, aber tatsächlich führte er dazu, dass der Benutzercode nicht kompiliert werden konnte.
Seltsamerweise unterscheidet Java dies nicht zur Laufzeit. Mit dem Validator des JVM kann eine kompilierte Klasse die SimpleInput :: Foo -Methode aufrufen, obwohl die geladene Klasse die aktualisierte Version von ThirdPartyBaseClass erbt und die KomplexInput -Schnittstelle implizit implementiert. Wenn Sie die Schuld geben möchten, können Sie den Compiler nur die Schuld geben. (Hinweis: Der Compiler und das Laufzeitverhalten sind inkonsistent)
Was haben wir daraus gelernt? Einfach ausgedrückt, überschreiben Sie nicht die Standardmethode der ursprünglichen Schnittstelle in einer anderen Schnittstelle. Schreiben Sie es nicht mit einer anderen Standardmethode um und schreiben Sie es nicht mit einer abstrakten Methode neu. Kurz gesagt, Sie sollten bei Verwendung der Standardmethode sehr vorsichtig sein. Obwohl sie die Schnittstellen der vorhandenen Sammlungsbibliotheken von Java erleichtern, können Sie Methodenaufrufe in der Vererbungsstruktur der Klasse tätigen, die im Wesentlichen die Komplexität erhöht. Vor Java 7 mussten Sie nur die lineare Klassenhierarchie durchqueren und sich den tatsächlichen Aufrufcode ansehen. Wenn Sie das Gefühl haben, dass Sie es wirklich brauchen, verwenden Sie die Standardmethode.
Das obige ist eine detaillierte Erklärung, warum Sie die Standardmethode von Java 8 mit Vorsicht verwenden sollten. Ich hoffe, es wird für das Lernen aller hilfreich sein.