Letzte Klasse
Wenn eine Klasse als endgültige Klasse definiert ist, bedeutet dies, dass die Klasse nicht von anderen Klassen geerbt werden kann, dh sie kann nach Erweiterung nicht verwendet werden. Andernfalls werden Sie während der Zusammenstellung einen Fehler erhalten.
Paket com.Iderzheng.FinalKeyword; public Final Class FinalClass {} // Fehler: Kann nicht von Final -Class -PackageClass erben. Java unterstützt die Definition der Klasse als endgültig, was gegen die Grundprinzipien der objektorientierten Programmierung zu verstoßen scheint. Andererseits stellt die beigefügte Klasse jedoch auch sicher, dass alle Methoden der Klasse festgelegt sind und es keine Unterläufe der Unterklasse dynamisch geladen werden. Dies bietet dem Compiler mehr Möglichkeiten, um zu optimieren. Das beste Beispiel ist Zeichenfolge, die endgültige Klasse. Der Java -Compiler kann String -Konstanten (die in doppelten Anführungszeichen enthaltenen String -Objekten direkt verwandeln und gleichzeitig den Bediener + Betrieb in neue Konstanten direkt optimieren, da die endgültige Änderung sicherstellt, dass keine Unterklassen unterschiedliche Werte für Spleißvorgänge zurückgeben.
Für alle verschiedenen Klassendefinitionen - Top -Level -Klassen (global oder paket sichtbar), können verschachtelte Klassen (interne oder statische verschachtelte Klassen) mit endgültigem geändert werden. Im Allgemeinen wird das Finale jedoch hauptsächlich verwendet, um Klassen zu ändern, die als öffentlich definiert wurden, da für Nicht-Global-Klassen Zugriffsmodifikatoren ihre Sichtbarkeit eingeschränkt haben, und es ist bereits schwierig, diese Klassen zu erben, sodass keine Schicht endgültiger Einschränkungen hinzugefügt werden muss.
Es wird auch erwähnt, dass anonyme Klassen zwar nicht vererbt werden können, sie jedoch vom Compiler nicht auf das endgültige Bestandteil beschränkt sind.
importieren java.lang.reflect.modifier; public class main {public static void main (String [] args) {runnable anonymous = new Runnable () {@Override public void run () {}}; System.out.println (modifier.isfinal (anonymous.getClass (). GetModifiers ())); }}Ausgabe:
FALSCH
Letzte Methode
Eng mit dem Konzept der Vererbung verwandt ist Polymorphismus, der den Unterschied zwischen den Konzepten von Übergeordnet und Versteck beinhaltet (die folgende werden gemeinsam als "Umschreiben" bezeichnet). Im Gegensatz zur Methodendefinition in C ++, ob virtuelles Schlüsselwort zur Unterklasse hinzugefügt wird, wird in Java die gleiche Methodensignatur überschrieben oder versteckt, um die gleiche Methodensignatur zu überschreiben, um die übergeordnete Klassenmethode zu überschreiben, wodurch eine versteckte Klassenmethode (statische Methode) (statische Methode), während Objektmethode (nicht statische Methode) nur überschreibt. Da Java den direkten Zugriff auf Klassenmethoden über Objekte ermöglicht, erlaubt Java keine Klassenmethoden und Objektmethoden, die gleiche Signatur in derselben Klasse zu haben.
Die endgültige Klasse definiert, dass die gesamte Klasse nicht vererbt werden kann, und sie bedeutet auch, dass alle Methoden in der Klasse nicht durch Unterklassen abgedeckt und verborgen werden können. Wenn die Klasse nicht durch die endgültige geändert wird, können einige Methoden weiterhin mithilfe des endgültigen geändert werden, um zu verhindern, dass diese Methoden durch Unterklassen neu geschrieben werden.
In ähnlicher Weise zerstört ein solches Design objektorientierter Polymorphismus, aber die endgültige Methode kann den Determinismus seiner Ausführung sicherstellen und so die Stabilität von Methodenaufrufen sicherstellen. In einigen Framework -Designs werden einige implementierte Methoden der abstrakten Klassen häufig auf endgültig beschränkt, da einige Treibercode im Framework auf diese Methoden beruhen, um die festgelegten Ziele zu erreichen, sodass es keine Unterklassen gibt, die sie abdecken.
Das folgende Beispiel zeigt die Rolle der endgültigen Modifikation in verschiedenen Arten von Methoden:
Paket com.Iderzheng.other; public class FinalMethods { public static void publicStaticMethod() { } public final void publicFinalMethod() { } public static final void publicStaticFinalMethod() { } protected final void protectedFinalMethod() { } protected static final void protectedStaticFinalMethod() { } final void finalMethod() { } static final void staticFinalMethod () {} private statische endgültige void privatestaticFinalMethod () {} private endgültige void privateFinalMethod () {}} Paket com.Iderzheng.FinalKeyword; import com.Iderzheng.other.finalMethods; öffentliche Klassenmethoden erweitern die endgültigen Methoden {public static void publicStaticMethod () {} // Fehler: Die öffentliche endgültige void Publicfinalmethod () {} // Fehler: Die öffentliche statische endgültige void publicstaticfinalMethode kann nicht überschieben. void publicStaticFinalMethod() { } // Error: cannot override protected final void protectedFinalMethod() { } // Error: cannot override protected static final void protectedStaticFinalMethod() { } final void finalMethod() { } static final void staticFinalMethod() { } private static final void privateStaticFinalMethod() {} private endgültige void privateFinalMethod () {}} Beachten Sie zunächst, dass im obigen Beispiel Finalmethoden und Methoden unter verschiedenen Paketen definiert werden. Für den ersten PublicStaticMethod schreibt die Unterklasse erfolgreich die statische Methode der übergeordneten Klasse um, aber weil es sich um eine statische Methode handelt, ist das, was passiert, tatsächlich "versteckt". Insbesondere wird die Implementierung in der Methodenklasse die Implementierung ausführen. Bei der Aufrufen von FinalMethods.publicstaticMethod () tritt die Implementierung nicht bei der polymorphen Belastung der Unterklasse auf, sondern verwendet direkt die Implementierung von FinalMethods. Bei der Verwendung von Unterklassen zum Zugriff auf Methoden ist die Sichtbarkeit der von der Elternklasse unterzeichneten Methoden daher versteckt.
Für die globale Methode PublicFinalMethod, wie in der endgültigen Modifikationsmethode beschrieben, ist es der Unterklasse verboten, sie zu überschreiben, und eine Ausnahme wird zur Kompilierungszeit ausgelöst. Der Methodenname ist jedoch in der Unterklasse gleich, hat jedoch einen Parameter, wie z.
In Intellij zeigt die IDE eine Warnung an die öffentlich -statische Finalmethod: "statische" Methode, die als "endgültig" deklariert wurde. Es scheint darüber überflüssig zu sein, aber aus dem Beispiel ist zu erkennen, dass das endgültige auch Unterklassendefinitionen von statischen Methoden zum Verstecken verbietet. In der tatsächlichen Entwicklung ist das Verhalten der Definition der gleichen statischen Methoden von Unterklassen und übergeordneten Klassen äußerst wünschenswert, da verborgene Methoden die Entwickler erfordern, dass die Verwendung verschiedener Klassennamen aufmerksam achten, um unterschiedliche Effekte zu definieren, was leicht zu Fehlern verursacht wird. Darüber hinaus können Sie innerhalb der Klasse statische Methoden direkt aufrufen, ohne den Klassennamen zu verwenden. Wenn der Entwickler erneut erbt, kann er die verborgene Existenz nicht bemerken. Bei der Verwendung der übergeordneten Klassenmethode wird er standardmäßig feststellen, dass dies nicht das erwartete Ergebnis ist. Daher sollten statische Methoden standardmäßig endgültig sein und nicht versteckt sein, so dass IDE der Meinung ist, dass es sich um eine unnötige Änderung handelt.
Die Methoden für geschützte Modifikationen und öffentliche Modifikationsmethoden in der übergeordneten Klasse sind für die Unterklasse sichtbar, so Es ist zu erwähnen, dass in der tatsächlichen Entwicklung geschützte statische Methoden im Allgemeinen selten definiert werden, da solche Methoden zu praktisch sind.
Für die Paketmethode der Elternklassen sind Unterklassen unter verschiedenen Paketen unsichtbar. Die private Methode wurde angepasst und nur die übergeordnete Klasse kann darauf zugreifen. Daher ermöglicht der Compiler Unterklassen, dieselbe Methode zu definieren. Dies bildet jedoch keine Überschreibung oder Versteck, da die übergeordnete Klasse diese Methoden durch Modifikatoren versteckt hat, die nicht durch Umschreiben von Unterklassen verursacht werden. Wenn sich die Unterklasse und die übergeordnete Klasse im selben Paket befinden, ist die Situation natürlich die gleiche wie die vorherige Öffentlichkeit und geschützt.
Warum ist die endgültige Methode effizient?
Die endgültige Methode verwendet den eingebetteten Mechanismus, um die Inline während der Zusammenstellung zu optimieren. Die Inline -Optimierung bezieht sich auf: Aufrufen von Funktionscode -Ersatz für den Zusammenstellung direkt während der Kompilierung, anstatt Funktionen zur Laufzeit aufzurufen. Inline muss wissen, welche Funktion am Ende beim Kompilieren verwendet werden soll. Offensichtlich ist es nicht möglich, es ohne endgültig zu verwenden. Nicht-Finale-Methoden können in Unterklassen neu geschrieben werden. Aufgrund eines möglichen Polymorphismus kann der Compiler den tatsächlichen Typ des Objekts nicht bestimmen, um die Methode in der Zukunft während der Kompilierungsphase aufzurufen, und er kann nicht bestimmen, welche Methode aufgerufen werden soll.
Endgültige Variable
Einfach ausgedrückt, die endgültige Variable in Java kann nur einmal initialisiert werden, und dann ist die Variable an den Wert gebunden. Diese Zuordnung muss jedoch nicht unbedingt sofort initialisiert werden, wenn die Variable definiert ist. Java unterstützt auch verschiedene Ergebnisse für endgültige Variablen durch bedingte Aussagen, die Variable kann jedoch in jedem Fall nur einmal zugewiesen werden.
Die endgültige Variable von Java ist jedoch keine absolute Konstante, da die Objektvariablen von Java nur Referenzwerte sind. Die endgültige Beendigung bedeutet daher nur, dass die Referenz nicht geändert werden kann und der Inhalt des Objekts weiterhin geändert werden kann. Im Vergleich zu C/C ++ - Zeigern ist es eher wie Typ * const variable als Typ const * Variable.
Java -Variablen können in zwei Kategorien unterteilt werden: lokale Variablen (lokale Variable) und Klassenmitgliedvariablen (Klassenfeld). Das Folgende ist ein Code, um ihre Initialisierungssituation getrennt einzusetzen.
Lokale Variable
Lokale Variablen beziehen sich hauptsächlich auf Variablen, die in Methoden definiert sind. Sie werden verschwinden und nach der Methode unzugänglich werden. Es gibt einen speziellen Fall, der in: Funktionsparameter unterteilt werden kann. Für diesen Fall ist seine Initialisierung an die Parameter gebunden, die in der Aufforderung der Funktion übergeben wurden.
Für andere lokale Variablen sind sie in der Methode definiert, und ihre Werte können bedingt initialisiert werden:
öffentliche String -Methode (endgültig boolean finalParam) {// Fehler: Der endgültige Parameter FinalParam kann nicht zugewiesen // FinalParam = true; Final Object FinalCocal = FinalParam? neues Objekt (): NULL; Final in Finalvar; if (finalCocal! = null) {FinalVar = 21; } else {FinalVar = 7; } // Fehler: Variable FinalVAR wurde möglicherweise bereits zugewiesen // FinalVar = 80; Final String Finalret; Switch (FinalVar) {Fall 21: Finalret = "me"; brechen; Fall 7: Finalret = "sie"; brechen; Standard: FinalRET = NULL; } return Finalret;} Aus dem obigen Beispiel ist ersichtlich, dass den durch die endgültigen geänderten Funktionsparametern keinen neuen Wert zugewiesen werden kann, aber anderen endgültigen lokalen Variablen können in einer bedingten Anweisung einen Wert zugewiesen. Dies bietet auch eine gewisse Flexibilität für das Finale.
Natürlich sollten alle Bedingungen in der bedingten Anweisung Zuordnungen zu endgültigen lokalen Variablen enthalten. Andernfalls erhalten Sie einen Fehler, dass die Variable möglicherweise nicht initialisiert wird.
öffentliche String -Methode (endgültiges Objekt FinalParam) {Final int FinalVar; if (finalParam! = null) {FinalVar = 21; } Final String Finalret; // Fehler: Variable FinalVAR wurde möglicherweise nicht initialisiert (FinalVAR) {Fall 21: Finalret = "me"; brechen; Fall 7: Finalret = "sie"; brechen; } // Fehler: Variable FinalRET wurde möglicherweise nicht initialisiert. Return Finalret;} Theoretisch sind lokale Variablen nicht erforderlich, um als endgültig definiert zu werden, und eine vernünftige Entwurfsmethode sollte in der Lage sein, lokale Variablen gut aufrechtzuerhalten. Bei Verwendung anonymer Funktionen, um Schließungen in Java -Methoden vorzunehmen, verlangt Java, dass die referenzierte lokale Variable als endgültig definiert werden muss:
öffentliche Runnable -Methode (String String) {int Integer = 12; return New Runnable () {@Override public void run () {// error: muss endgültiges System.out.println (String) deklariert werden; // Fehler: muss endgültig system.out.println (Integer) deklariert werden; }};}Klassenfeld
Klassenmitgliedvariablen können tatsächlich in zwei Typen unterteilt werden: statisch und nicht statisch. Für statische Klassenmitgliedsvariablen, da sie sich mit Klassen beziehen, können sie nicht nur zur Definitionszeit direkt initialisiert werden, sondern auch in einen statischen Block platziert werden und kann komplexere Anweisungen ausführen:
Paket com.Iderzheng.FinalKeyword; import Java.util.hashset; Import Java.util.linkedHashset; Import Java.util.set; public class staticfinalfields {static final int static_final_init_inline = 7; Static Final Set <Ganzzahl> static_final_init_static_block; / ** statischer Block **/ static {if (System.currentTimemillis () % 2 == 0) {static_final_init_static_block = new Hashset <> (); } else {static_final_init_static_block = new LinkedHashset <> (); } Static_final_init_static_block.add (7); Static_final_init_static_block.add (21); }}Es gibt auch nicht statische Blöcke in Java, die nicht statische Mitgliedsvariablen initialisieren können, aber für diese Variablen werden sie häufig zur Initialisierung im Konstruktor platziert. Natürlich muss sichergestellt werden, dass jede endgültige Variable einmal im Konstruktor initialisiert wird. Wenn andere Konstruktoren durch diese () aufgerufen werden, können diese endgültigen Variablen im Konstruktor nicht mehr zugewiesen werden.
Paket com.Iderzheng.FinalKeyword; öffentliche Klasse Finalfields {Final Long Final_init_inline = System.currentTimemillis (); Final Long Final_init_block; Final Long Final_init_Constructor; / ** Anfangsblock **/ {final_init_block = system.nanotime (); } Finalfields () {this (217); } Finalfields (boolean bool) {final_init_constructor = 721; } Finalfields (long init) {final_init_constructor = init; }}Wenn die endgültige Änderung von Klassen (Klasse) und Methoden (Methode) verwendet wird, wirkt sich hauptsächlich die objektorientierte Vererbung aus. Ohne Erbschaft wird es nicht abhängig vom Code der Unterklasse in der übergeordneten Klasse geben. Bei der Änderung des Codes während der Wartung muss er nicht prüfen, ob die Implementierung der Unterklasse zerstört wird, was ihn bequemer macht. Wenn es in einer Variablen verwendet wird, stellt Java sicher, dass der variable Wert nicht geändert wird. Wenn ein weiteres Design sicherstellt, dass die Mitglieder der Klasse nicht geändert werden können, kann die gesamte Variable in eine Konstante umgewandelt werden, was für die Programmierung von Multi-Threaded sehr vorteilhaft ist. Daher wirkt sich das Finale sehr gut auf die Code -Wartung aus.