Zunächst empfehle ich diesen Artikel: Java: Wann wird eine endgültige Klasse erstellt?
Wenn ja, wann verwenden sie es, damit ich es besser verstehen und wissen kann, wann ich es verwenden soll.
Eine final
Klasse ist einfach eine Klasse, die nicht erweitert werden kann .
(Dies bedeutet nicht, dass alle Verweise auf Objekte der Klasse so tun würden, als ob sie als deklariert wären final
.)
Wenn es nützlich ist, eine Klasse als endgültig zu deklarieren, wird in den Antworten auf diese Frage Folgendes behandelt:
Wenn Java objektorientiert ist und Sie eine Klasse deklarieren final
, stoppt es dann nicht die Idee, dass eine Klasse die Eigenschaften von Objekten hat?
In gewissem Sinne ja.
Indem Sie eine Klasse als endgültig markieren, deaktivieren Sie eine leistungsstarke und flexible Funktion der Sprache für diesen Teil des Codes. Einige Klassen sollten jedoch nicht (und können in bestimmten Fällen auch nicht) so gestaltet werden, dass Unterklassen auf gute Weise berücksichtigt werden. In diesen Fällen ist es sinnvoll, die Klasse als endgültig zu markieren, obwohl dies die OOP einschränkt. (Denken Sie jedoch daran, dass eine Abschlussklasse noch eine andere Nicht-Abschlussklasse erweitern kann.)
In Java können Elemente mit dem
final
Modifikator nicht geändert werden!Dies umfasst endgültige Klassen, endgültige Variablen und endgültige Methoden:
quelle
final
Modifikator nicht geändert werden!" Ist zu kategorisch und in der Tat nicht ganz korrekt. Wie Grady Booch es ausdrückte: "Ein Objekt hat Zustand, Verhalten und Identität". Obwohl wir die Identität eines Objekts nicht ändern können, sobald seine Referenz als endgültig markiert wurde, haben wir die Möglichkeit, seinen Status zu ändern, indem wir seinen Nichtfeldern neue Werte zuweisenfinal
(vorausgesetzt natürlich, es hat sie.) Jeder, der es ist Wenn Sie planen, eine Oracle Java-Zertifizierung (wie 1Z0-808 usw.) zu erhalten, sollten Sie dies berücksichtigen, da möglicherweise Fragen zu diesem Aspekt in der Prüfung enthalten sind ...Ein Szenario, in dem final aus Sicherheitsgründen wichtig ist, wenn Sie die Vererbung einer Klasse verhindern möchten . Auf diese Weise können Sie sicherstellen, dass der von Ihnen ausgeführte Code nicht von jemandem überschrieben werden kann.
Ein anderes Szenario dient der Optimierung: Ich erinnere mich anscheinend, dass der Java-Compiler einige Funktionsaufrufe von endgültigen Klassen einfügt. Wenn Sie also aufrufen
a.x()
und a deklariert istfinal
, wissen wir zur Kompilierungszeit, wie der Code aussehen wird, und können ihn in die aufrufende Funktion integrieren. Ich habe keine Ahnung, ob dies tatsächlich getan wird, aber mit final ist es eine Möglichkeit.quelle
Das beste Beispiel ist
Das ist eine unveränderliche Klasse und kann nicht erweitert werden. Natürlich gibt es mehr als nur das Klassenfinale unveränderlich zu machen.
quelle
Relevante Lektüre: Das Open-Closed-Prinzip von Bob Martin.
Schlüsselzitat:
Das
final
Schlüsselwort ist das Mittel, um dies in Java zu erzwingen, unabhängig davon, ob es für Methoden oder für Klassen verwendet wird.quelle
final
die Klasse nicht deklariert, um sie zu erweitern, anstatt sie zu öffnen? Oder nehme ich es zu wörtlich?final
einer Klassen- / Methodendeklaration nicht sinnvoll, wenn der Implementierungscode zur Änderung geschlossen, aber zur Erweiterung durch Vererbung geöffnet werden soll.Wenn Sie sich die Klassenhierarchie als Baum vorstellen (wie in Java), können abstrakte Klassen nur Zweige sein, und endgültige Klassen können nur Blätter sein. Klassen, die in keine dieser Kategorien fallen, können sowohl Zweige als auch Blätter sein.
Es gibt hier keine Verletzung der OO-Prinzipien, final bietet einfach eine schöne Symmetrie.
In der Praxis möchten Sie final verwenden, wenn Ihre Objekte unveränderlich sein sollen oder wenn Sie eine API schreiben, um den Benutzern der API zu signalisieren, dass die Klasse nur nicht für die Erweiterung vorgesehen ist.
quelle
Das Schlüsselwort
final
selbst bedeutet, dass etwas endgültig ist und in keiner Weise geändert werden soll. Wenn eine Klasse markiertfinal
ist, kann sie nicht erweitert oder unterklassifiziert werden. Aber die Frage ist, warum wir eine Klasse markierenfinal
? IMO gibt es verschiedene Gründe:Ich habe gehört, dass die Markierungsklasse
final
die Effizienz verbessert, aber ehrlich gesagt konnte ich nicht feststellen, dass dieses Argument viel Gewicht hat.Vielleicht ja, aber manchmal ist das der beabsichtigte Zweck. Manchmal tun wir dies, um größere Vorteile der Sicherheit usw. zu erzielen, indem wir die Fähigkeit dieser Klasse opfern, erweitert zu werden. Eine Abschlussklasse kann jedoch bei Bedarf noch eine Klasse erweitern.
Nebenbei bemerkt sollten wir die Komposition der Vererbung vorziehen, und das
final
Schlüsselwort hilft tatsächlich bei der Durchsetzung dieses Prinzips.quelle
Seien Sie vorsichtig, wenn Sie eine Klasse "final" machen. Wenn Sie einen Komponententest für eine Abschlussklasse schreiben möchten, können Sie diese Abschlussklasse nicht unterordnen, um die in Michael C. Feathers 'Buch "Effektiv mit Legacy-Code arbeiten" beschriebene Technik zum Unterbrechen von Abhängigkeiten "Unterklassen- und Überschreibungsmethode" zu verwenden. . In diesem Buch sagte Feathers: "Im Ernst, es ist leicht zu glauben, dass versiegelt und endgültig ein falscher Fehler sind, dass sie niemals zu Programmiersprachen hinzugefügt werden sollten. Aber der wahre Fehler liegt bei uns. Wenn wir direkt davon abhängen." Bibliotheken, die außerhalb unserer Kontrolle liegen, bitten wir nur um Ärger. "
quelle
final class
kann vermeiden, dass die öffentliche API beschädigt wird, wenn Sie neue Methoden hinzufügenAngenommen,
Base
Sie tun in Version 1 Ihrer Klasse Folgendes:und ein Kunde tut:
Wenn Sie dann in Version 2 eine
method
Methode hinzufügen möchten zuBase
:es würde den Client-Code brechen.
Wenn wir
final class Base
stattdessen verwendet hätten, hätte der Client nicht erben können, und das Hinzufügen von Methoden würde die API nicht beschädigen.quelle
Wenn die Klasse markiert ist
final
, bedeutet dies, dass die Struktur der Klasse durch nichts Externes geändert werden kann. Dies ist am sichtbarsten, wenn Sie eine traditionelle polymorphe Vererbung durchführen, die im Grundeclass B extends A
einfach nicht funktioniert. Dies ist im Grunde eine Möglichkeit, einige Teile Ihres Codes zu schützen (soweit) .Zur Verdeutlichung markiert
final
das Markieren einer Klasse ihre Felder nichtfinal
als solche und schützt daher nicht die Objekteigenschaften, sondern die tatsächliche Klassenstruktur.quelle
So adressieren Sie das endgültige Klassenproblem:
Es gibt zwei Möglichkeiten, ein Klassenfinale zu erreichen. Das erste besteht darin, das Schlüsselwort final in der Klassendeklaration zu verwenden:
Die zweite Möglichkeit, ein Klassenfinale zu erreichen, besteht darin, alle Konstruktoren als privat zu deklarieren:
Wenn Sie es als endgültig markieren, sparen Sie sich die Mühe, wenn Sie feststellen, dass es sich tatsächlich um ein Finale handelt, um den Blick auf diese Testklasse zu demonstrieren. sieht auf den ersten Blick öffentlich aus.
Da der einzige Konstruktor der Klasse privat ist, ist es leider unmöglich, diese Klasse zu erweitern. Im Fall der Testklasse gibt es keinen Grund, warum die Klasse endgültig sein sollte. Die Testklasse ist ein gutes Beispiel dafür, wie implizite Abschlussklassen Probleme verursachen können.
Sie sollten es also als endgültig markieren, wenn Sie eine Klasse implizit endgültig machen, indem Sie ihren Konstruktor privat machen.
quelle
Eine Abschlussklasse ist eine Klasse, die nicht erweitert werden kann. Außerdem könnten Methoden als endgültig deklariert werden, um anzuzeigen, dass sie nicht von Unterklassen überschrieben werden können.
Das Verhindern, dass die Klasse in Unterklassen unterteilt wird, kann besonders nützlich sein, wenn Sie APIs oder Bibliotheken schreiben und eine Erweiterung vermeiden möchten, um das Basisverhalten zu ändern.
quelle
Ein Vorteil, eine Klasse als endgültig zu halten:
Die String-Klasse wird endgültig gehalten, damit niemand ihre Methoden überschreiben und die Funktionalität ändern kann. zB kann niemand die Funktionalität der length () -Methode ändern. Es wird immer die Länge eines Strings zurückgegeben.
Der Entwickler dieser Klasse wollte, dass niemand die Funktionalität dieser Klasse ändert, deshalb behielt er sie als endgültig bei.
quelle
Ja, manchmal möchten Sie dies jedoch aus Sicherheits- oder Geschwindigkeitsgründen. Es ist auch in C ++ gemacht. Es kann nicht sein , dass anwendbar für Programme, aber um so mehr für Gerüste. http://www.glenmccl.com/perfj_025.htm
quelle
In Java wird das endgültige Schlüsselwort für die folgenden Gelegenheiten verwendet.
quelle
Abschlussklassen können nicht verlängert werden. Wenn Sie also möchten, dass sich eine Klasse auf eine bestimmte Weise verhält und die Methoden nicht von jemandem überschrieben werden (mit möglicherweise weniger effizientem und schädlicherem Code), können Sie die gesamte Klasse als endgültige oder spezifische Methode deklarieren, die Sie nicht sein möchten geändert.
Da das Deklarieren einer Klasse nicht verhindert, dass eine Klasse instanziiert wird, bedeutet dies nicht, dass die Klasse nicht die Eigenschaften eines Objekts aufweist. Es ist nur so, dass Sie sich an die Methoden halten müssen, wie sie in der Klasse deklariert sind.
quelle
Stellen Sie sich FINAL als das "Ende der Reihe" vor - dieser Typ kann keine Nachkommen mehr hervorbringen. Wenn Sie es so sehen, gibt es unzählige reale Szenarien, auf die Sie stoßen müssen, bei denen Sie der Klasse einen Zeilenende-Marker markieren müssen. Es handelt sich um domänengesteuertes Design. Wenn Ihre Domain verlangt, dass eine bestimmte ENTITY (Klasse) keine Unterklassen erstellen kann, markieren Sie sie als FINAL.
Ich sollte beachten, dass Sie nichts daran hindert, eine Klasse zu erben, die als endgültig gekennzeichnet werden sollte. Dies wird jedoch im Allgemeinen als "Missbrauch der Vererbung" klassifiziert und erfolgt, weil Sie meistens eine Funktion von der Basisklasse in Ihrer Klasse erben möchten.
Der beste Ansatz besteht darin, sich die Domäne anzusehen und sie Ihre Entwurfsentscheidungen bestimmen zu lassen.
quelle
Wie oben erwähnt, können Sie die Funktionalität der Methode als endgültig deklarieren, wenn Sie möchten, dass niemand die Funktionalität der Methode ändern kann.
Beispiel: Anwendungsserver-Dateipfad zum Herunterladen / Hochladen, Aufteilen der Zeichenfolge basierend auf dem Offset. Solche Methoden können Sie als endgültig deklarieren, damit diese Methodenfunktionen nicht geändert werden. Wenn Sie solche endgültigen Methoden in einer separaten Klasse möchten, definieren Sie diese Klasse als endgültige Klasse. Die letzte Klasse verfügt also über alle endgültigen Methoden, wobei die endgültige Methode in der nicht endgültigen Klasse deklariert und definiert werden kann.
quelle
Die Android Looper-Klasse ist ein gutes praktisches Beispiel dafür. http://developer.android.com/reference/android/os/Looper.html
Die Looper-Klasse bietet bestimmte Funktionen, die NICHT von einer anderen Klasse überschrieben werden sollen. Daher hier keine Unterklasse.
quelle
Angenommen, Sie haben eine
Employee
Klasse mit einer Methodegreet
. Wenn diegreet
Methode aufgerufen wird, wird sie einfach gedrucktHello everyone!
. Das ist also das erwartete Verhalten dergreet
MethodeLassen Sie nun die
GrumpyEmployee
UnterklasseEmployee
und überschreiben Sie diegreet
Methode wie unten gezeigt.Schauen Sie sich jetzt im folgenden Code die an
sayHello
Methode an. Es nimmt dieEmployee
Instanz als Parameter und ruft die greet-Methode auf, in der Hoffnung, dass sie sagen würde,Hello everyone!
aber was wir bekommen, istGet lost!
. Diese Verhaltensänderung ist auf zurückzuführenEmployee grumpyEmployee = new GrumpyEmployee();
Diese Situation kann vermieden werden, wenn die
Employee
Klasse gemacht wurdefinal
. Stellen Sie sich vor, wie viel Chaos ein frecher Programmierer verursachen könnte, wennString
Class nicht als deklariert würdefinal
.quelle
Die Abschlussklasse kann nicht weiter erweitert werden. Wenn wir eine Klasse in Java nicht vererbbar machen müssen, können wir diesen Ansatz verwenden.
Wenn wir nur bestimmte Methoden in einer Klasse festlegen müssen, um nicht überschrieben zu werden, können wir ihnen nur das letzte Schlüsselwort vorlegen. Dort ist die Klasse noch vererbbar.
quelle
Bei der Objektorientierung geht es nicht um Vererbung, sondern um Kapselung. Und die Vererbung unterbricht die Kapselung.
In vielen Fällen ist es durchaus sinnvoll, ein Klassenfinale zu erklären. Jedes Objekt, das einen „Wert“ wie eine Farbe oder einen Geldbetrag darstellt, kann endgültig sein. Sie stehen alleine da.
Wenn Sie Bibliotheken schreiben, machen Sie Ihre Klassen endgültig, es sei denn, Sie rücken sie ausdrücklich ein, um sie abzuleiten. Andernfalls können Personen Ihre Klassen ableiten und Methoden überschreiben, wodurch Ihre Annahmen / Invarianten verletzt werden. Dies kann auch Auswirkungen auf die Sicherheit haben.
Joshua Bloch in „Effective Java“ empfiehlt, explizit für die Vererbung zu entwerfen oder zu verbieten, und er stellt fest, dass das Entwerfen für die Vererbung nicht so einfach ist.
quelle