In Java verwenden wir final
Schlüsselwörter mit Variablen, um anzugeben, dass deren Werte nicht geändert werden sollen. Aber ich sehe, dass Sie den Wert im Konstruktor / in den Methoden der Klasse ändern können. Wenn die Variable static
dann wieder ist, handelt es sich um einen Kompilierungsfehler.
Hier ist der Code:
import java.util.ArrayList;
import java.util.List;
class Test {
private final List foo;
public Test()
{
foo = new ArrayList();
foo.add("foo"); // Modification-1
}
public static void main(String[] args)
{
Test t = new Test();
t.foo.add("bar"); // Modification-2
System.out.println("print - " + t.foo);
}
}
Der obige Code funktioniert einwandfrei und ohne Fehler.
Ändern Sie nun die Variable wie folgt static
:
private static final List foo;
Jetzt ist es ein Kompilierungsfehler. Wie funktioniert das final
wirklich?
Antworten:
Sie dürfen immer eine Variable initialisieren
final
. Der Compiler stellt sicher, dass Sie dies nur einmal tun können.Beachten Sie, dass das Aufrufen von Methoden für ein in einer
final
Variablen gespeichertes Objekt nichts mit der Semantik von zu tun hatfinal
. Mit anderen Worten: Esfinal
geht nur um die Referenz selbst und nicht um den Inhalt des referenzierten Objekts.Java hat kein Konzept der Objektveränderlichkeit; Dies wird durch sorgfältiges Entwerfen des Objekts erreicht und ist alles andere als trivial.
quelle
final
. Veränderbare Objekte können ebenfalls stapelweise zugewiesen werden.final
Felder können zwar bei der Fluchtanalyse hilfreich sein, aber das ist ein ziemlich indirekter Weg. Beachten Sie auch, dass effektiv endgültige Variablen die gleiche Behandlung haben wie diefinal
im Quellcode markierten .final
ist in der Klassendatei vorhanden und hat erhebliche semantische Konsequenzen für eine optimierte Laufzeit. Dies kann auch Kosten verursachen , da das JLS eine starke Garantie für die Konsistenz derfinal
Felder eines Objekts hat. Beispielsweise muss der ARM-Prozessor am Ende jedes Konstruktors einer Klasse mitfinal
Feldern einen expliziten Speicherbarrierebefehl verwenden. Auf anderen Prozessoren ist dies jedoch nicht erforderlich.Dies ist eine beliebte Interviewfrage . Mit diesen Fragen versucht der Interviewer herauszufinden, wie gut Sie das Verhalten von Objekten in Bezug auf Konstruktoren, Methoden, Klassenvariablen (statische Variablen) und Instanzvariablen verstehen.
Im obigen Fall haben wir einen Konstruktor für 'Test' definiert und ihm eine 'setFoo'-Methode gegeben.
Informationen zum Konstruktor: Der Konstruktor kann nur einmal pro Objekterstellung mithilfe des
new
Schlüsselworts aufgerufen werden . Sie können den Konstruktor nicht mehrmals aufrufen, da der Konstruktor nicht dafür ausgelegt ist.Über die Methode: Eine Methode kann so oft aufgerufen werden, wie Sie möchten (auch nie), und der Compiler weiß es.
Szenario 1
foo
ist ein Instanzvariable. Wenn wir einTest
Klassenobjekt erstellenfoo
, wird die Instanzvariable in das Objekt derTest
Klasse kopiert . Wenn wirfoo
innerhalb des Konstruktors zuweisen , weiß der Compiler, dass der Konstruktor nur einmal aufgerufen wird, sodass es kein Problem gibt, ihn innerhalb des Konstruktors zuzuweisen .Wenn wir
foo
innerhalb einer Methode zuweisen , weiß der Compiler, dass eine Methode mehrmals aufgerufen werden kann, was bedeutet, dass der Wert mehrmals geändert werden muss, was für einefinal
Variable nicht zulässig ist. Der Compiler entscheidet also, dass der Konstruktor eine gute Wahl ist! Sie können einer endgültigen Variablen nur einmal einen Wert zuweisen.Szenario 2
foo
ist jetzt eine statische Variable. Wenn wir eine Instanz einerTest
Klasse erstellen ,foo
wird diese nicht in das Objekt kopiert, da siefoo
statisch ist. Jetztfoo
ist nicht eine unabhängige Eigenschaft jedes Objekts. Dies ist eine Eigenschaft derTest
Klasse. Aberfoo
kann durch mehrere Objekte zu erkennen und , wenn jedes Objekt , das unter Verwendung des erstelltenew
Schlüsselwort , das letztlich das wird aufrufeTest
Konstruktor , die den Wert zum Zeitpunkt der mehrere Objekterstellung ändert (Denken Sie daran ,static foo
sich in jedem Objekt nicht kopiert, sondern zwischen mehreren Objekten gemeinsam .)Szenario 3
Oben
Modification-2
ist von Ihrer Frage. Im obigen Fall ändern Sie nicht das erste referenzierte Objekt, sondern fügen Inhalte hinzu,foo
die zulässig sind. Der Compiler beschwert sich, wenn Sie versuchennew ArrayList()
, derfoo
Referenzvariablen a zuzuweisen .Regel Wenn Sie eine
final
Variable initialisiert haben , können Sie sie nicht so ändern, dass sie auf ein anderes Objekt verweist. (In diesem FallArrayList
)Finale Klassen können nicht unterklassiert werden
final Methoden außer Kraft gesetzt werden kann. (Dieses Verfahren ist in übergeordneter Klasse)
final Methoden überschreiben können. (Lesen Sie dies grammatikalisch. Diese Methode gehört zu einer Unterklasse.)
quelle
foo
dies trotz der endgültigen Bezeichnung mehrmals festgelegt wird, wennfoo
es in der Testklasse festgelegt ist und mehrere Testinstanzen erstellt werden?foo
kann .. mehrere Objekte sein). Ist das gemein, wenn ich zu einem Zeitpunkt mehr Objekte zu erstellen, dann , welchem Objekt initialisiert letzten Variable ist bei der Ausführung abhängt?final
der Speicheradresse zuweisen, auf die verwiesen wird, auffoo
die sich eine ArrayList bezieht . Sie weisen nichtfinal
die Speicheradresse zu , auf die das erste Element vonfoo
(oder ein anderes Element in dieser Angelegenheit) verweist . Daher können Sie nicht ändern,foo
aber Sie können ändernfoo[0]
.foo = new ArrayList();
-foo
sich auf die statische Variable bezieht, da wir uns in derselben Klasse befinden.final
eine Variable als dasconst
Schlüsselwort in C ++ vorzustellen?Das endgültige Schlüsselwort hat zahlreiche Verwendungsmöglichkeiten:
Andere Verwendung:
Eine statische Klassenvariable ist ab dem Start der JVM vorhanden und sollte in der Klasse initialisiert werden. Die Fehlermeldung wird in diesem Fall nicht angezeigt.
quelle
static
(solange dies nicht derfinal
Fall ist). In diesem Wiki finden Sie den Unterschied zwischen Zuweisung und Initialisierung .Das
final
Schlüsselwort kann je nach Verwendungszweck auf zwei verschiedene Arten interpretiert werden:Werttypen: Für
int
s,double
s usw. wird sichergestellt, dass sich der Wert nicht ändern kann.Referenztypen: Stellt bei Verweisen auf Objekte
final
sicher, dass die Referenz niemals ändert, was bedeutet, dass sie immer auf dasselbe Objekt verweist. Es gibt keinerlei Garantie dafür, dass die Werte innerhalb des Objekts, auf die Bezug genommen wird, gleich bleiben.Stellt daher
final List<Whatever> foo;
sicher, dassfoo
immer auf dieselbe Liste Bezug genommen wird, der Inhalt dieser Liste sich jedoch im Laufe der Zeit ändern kann.quelle
Wenn Sie
foo
statisch machen , müssen Sie es im Klassenkonstruktor (oder in der Zeile, in der Sie es definieren) wie in den folgenden Beispielen initialisieren.Klassenkonstruktor (keine Instanz):
In der Reihe:
Das Problem hierbei ist nicht, wie der
final
Modifikator funktioniert, sondern wie derstatic
Modifikator funktioniert.Der
final
Modifikator erzwingt eine Initialisierung Ihrer Referenz bis zum Abschluss des Aufrufs Ihres Konstruktors (dh Sie müssen ihn im Konstruktor initialisieren).Wenn Sie ein Attribut inline initialisieren, wird es initialisiert, bevor der Code ausgeführt wird, den Sie für den Konstruktor definiert haben, sodass Sie die folgenden Ergebnisse erhalten:
foo
iststatic
,foo = new ArrayList()
wird es ausgeführt, bevor derstatic{}
Konstruktor ausgeführt wird, den Sie für Ihre Klasse definiert habenfoo
nicht der Fall iststatic
,foo = new ArrayList()
wird es ausgeführt, bevor Ihr Konstruktor ausgeführt wirdWenn Sie ein Attribut nicht inline
final
initialisieren, erzwingt der Modifikator, dass Sie es initialisieren und dass Sie dies im Konstruktor tun müssen. Wenn Sie auch einenstatic
Modifikator haben, ist der Konstruktor, in dem Sie das Attribut initialisieren müssen, der Initialisierungsblock der Klasse:static{}
.Der Fehler, den Sie in Ihrem Code erhalten, beruht auf der Tatsache, dass er
static{}
beim Laden der Klasse ausgeführt wird, bevor Sie ein Objekt dieser Klasse instanziieren. Daher haben Sie beim Erstellenfoo
der Klasse nicht initialisiert .Stellen Sie sich den
static{}
Block als Konstruktor für ein Objekt vom Typ vorClass
. Hier müssen Sie die Initialisierung Ihrerstatic final
Klassenattribute durchführen (falls dies nicht inline erfolgt).Randnotiz:
Der
final
Modifikator stellt die Konstanz nur für primitive Typen und Referenzen sicher.Wenn Sie ein
final
Objekt deklarieren , erhalten Sie einefinal
Referenz auf dieses Objekt, aber das Objekt selbst ist nicht konstant.Was Sie erzielen wirklich , wenn eine Deklaration
final
Attribut ist , dass, sobald Sie ein Objekt für einen speziellen Zweck zu erklären (wie die ,final List
dass Sie erklärt haben), das und nur das Objekt wird für diesen Zweck verwendet werden: Sie Änderungen nicht in der LageList foo
zu eine andereList
, aber Sie können Ihre ändern,List
indem Sie Elemente hinzufügen / entfernen (die vonList
Ihnen verwendeten Elemente sind dieselben, nur wenn der Inhalt geändert wird).quelle
Dies ist eine sehr gute Interviewfrage. Manchmal werden Sie sogar gefragt, was der Unterschied zwischen einem endgültigen Objekt und einem unveränderlichen Objekt ist.
1) Wenn jemand ein endgültiges Objekt erwähnt, bedeutet dies, dass die Referenz nicht geändert werden kann, aber ihr Status (Instanzvariablen) kann geändert werden.
2) Ein unveränderliches Objekt ist ein Objekt, dessen Zustand nicht geändert werden kann, dessen Referenz jedoch geändert werden kann. Ex:
Die Referenzvariable x kann geändert werden, um auf eine andere Zeichenfolge zu verweisen, der Wert von "abc" kann jedoch nicht geändert werden.
3) Instanzvariablen (nicht statische Felder) werden beim Aufruf eines Konstruktors initialisiert. So können Sie Werte für Ihre Variablen in einem Konstruktor initialisieren.
4) "Aber ich sehe, dass Sie den Wert im Konstruktor / in den Methoden der Klasse ändern können". - Sie können es nicht innerhalb einer Methode ändern.
5) Eine statische Variable wird beim Laden der Klasse initialisiert. Sie können also nicht innerhalb eines Konstruktors initialisieren, dies muss bereits vorher erfolgen. Sie müssen also einer statischen Variablen während der Deklaration selbst Werte zuweisen .
quelle
Das
final
Schlüsselwort in Java wird verwendet, um den Benutzer einzuschränken. Das Java-final
Schlüsselwort kann in vielen Zusammenhängen verwendet werden. Finale kann sein:Das
final
Schlüsselwort kann mit den Variablen angewendet werden. Einefinal
Variable, die keinen Wert hat, wird als leerefinal
Variable oder nicht initialisiertefinal
Variable bezeichnet. Es kann nur im Konstruktor initialisiert werden. Esfinal
kannstatic
auch die leere Variable sein, die nur imstatic
Block initialisiert wird .Java letzte Variable:
Wenn Sie eine Variable als
final
festlegen, können Sie den Wert derfinal
Variablen nicht ändern (er ist konstant).Beispiel einer
final
VariablenEs gibt eine endgültige Geschwindigkeitsbegrenzung für die Variable. Wir werden den Wert dieser Variablen ändern, sie kann jedoch nicht geändert werden, da die endgültige Variable, der einmal ein Wert zugewiesen wurde, niemals geändert werden kann.
Java-Abschlussklasse:
Wenn Sie eine Klasse als
final
erstellen, können Sie sie nicht erweitern .Beispiel für die Abschlussklasse
Java endgültige Methode:
Wenn Sie eine Methode als endgültig festlegen, können Sie sie nicht überschreiben .
Beispiel für eine
final
Methode (run () in Honda kann run () in Bike nicht überschreiben)geteilt von: http://www.javatpoint.com/final-keyword
quelle
Erwähnenswert sind einige einfache Definitionen:
Klassen / Methoden
Variablen
final
Vermeiden Sie grundsätzlich das Überschreiben / Überschreiben durch irgendetwas (Unterklassen, Variable "Neuzuweisung"), je nach Fall.quelle
final
ist ein reserviertes Schlüsselwort in Java, um den Benutzer einzuschränken. Es kann auf Mitgliedsvariablen, Methoden, Klassen und lokale Variablen angewendet werden. Endvariablen werdenstatic
in Java häufig mit dem Schlüsselwort deklariert und als Konstanten behandelt. Zum Beispiel:Wenn wir das
final
Schlüsselwort mit einer Variablendeklaration verwenden, kann der in dieser Variablen gespeicherte Wert nicht geändert werden.Zum Beispiel:
Hinweis : Eine als final deklarierte Klasse kann nicht erweitert oder vererbt werden (dh es kann keine Unterklasse der Superklasse geben). Es ist auch gut zu beachten, dass als final deklarierte Methoden nicht von Unterklassen überschrieben werden können.
Die Vorteile der Verwendung des endgültigen Schlüsselworts werden in diesem Thread behandelt .
quelle
the value stored inside that variable cannot be changed latter
ist teilweise wahr. Dies gilt nur für primitive Datentypen.final
Wenn ein Objekt wie eine Arrayliste erstellt wird, kann sich sein Wert ändern, nicht jedoch die Referenz. Vielen Dank!Angenommen, Sie haben zwei Sparbüchsen, rot und weiß. Sie weisen diesen Sparbüchsen nur zwei Kinder zu und sie dürfen ihre Geldboxen nicht austauschen. Sie haben also rote oder weiße Sparbüchsen (endgültig). Sie können die Schachtel nicht ändern, aber Sie können Geld auf Ihre Schachtel legen. Niemand kümmert sich darum (Änderung-2).
quelle
Lesen Sie alle Antworten.
Es gibt einen anderen Benutzerfall, in dem
final
Schlüsselwörter verwendet werden können, z. B. in einem Methodenargument:Kann für Variablen verwendet werden, die nicht geändert werden sollen.
quelle
Wenn Sie es statisch endgültig machen, sollte es in einem statischen Initialisierungsblock initialisiert werden
quelle
Das
final
Schlüsselwort gibt an, dass eine Variable nur einmal initialisiert werden darf. In Ihrem Code führen Sie nur eine Initialisierung von final durch, damit die Bedingungen erfüllt sind. Diese Anweisung führt die Einzelinitialisierung von durchfoo
. Beachten Sie, dassfinal
! = Unveränderlich bedeutet, dass sich die Referenz nicht ändern kann.Wenn Sie
foo
als deklarierenstatic final
, muss die Variable beim Laden der Klasse initialisiert werden und kann sich beim Initialisieren nicht auf die Instanziierung (auch als Aufruf des Konstruktors bezeichnet) verlassenfoo
da statische Felder ohne Instanz einer Klasse verfügbar sein müssen. Es gibt keine Garantie dafür, dass der Konstruktor vor Verwendung des statischen Felds aufgerufen wurde.Wenn Sie Ihre Methode unter dem
static final
Szenario ausführen , wird dieTest
Klasse vor dem Instanziieren geladen. Zut
diesem Zeitpunkt gibt es keine Instanziierung derfoo
Bedeutung, dass sie nicht initialisiert wurde. Daherfoo
wird sie für alle Objekte auf den Standardwert gesetztnull
. An dieser Stelle gehe ich davon aus, dass Ihr Code ein löst,NullPointerException
wenn Sie versuchen, ein Element zur Liste hinzuzufügen.quelle
Zunächst ist hier die Stelle in Ihrem Code, an der Sie foo initialisieren (dh zum ersten Mal zuweisen):
foo ist ein Objekt (mit Typ List), also ein Referenztyp , kein Werttyp (wie int). Als solches enthält es einen Verweis auf einen Speicherort (z. B. 0xA7D2A834), an dem Ihre Listenelemente gespeichert sind. Linien wie diese
Ändern Sie nicht den Wert von foo (der wiederum nur eine Referenz auf einen Speicherort ist). Stattdessen fügen sie einfach Elemente zu dem Speicherort hinzu, auf den verwiesen wird. Um das endgültige Schlüsselwort zu verletzen , müssten Sie erneut versuchen, foo wie folgt neu zuzuweisen:
Das würde Ihnen einen Kompilierungsfehler geben.
Überlegen Sie sich nun, was passiert, wenn Sie das statische Schlüsselwort hinzufügen .
Wenn Sie NICHT über das statische Schlüsselwort verfügen, verfügt jedes Objekt, das die Klasse instanziiert, über eine eigene Kopie von foo. Daher weist der Konstruktor einer leeren, frischen Kopie der Variablen foo einen Wert zu, was vollkommen in Ordnung ist.
Wenn Sie jedoch das statische Schlüsselwort haben, ist nur ein foo im Speicher vorhanden, der der Klasse zugeordnet ist. Wenn Sie zwei oder mehr Objekte erstellen würden, würde der Konstruktor versuchen, dieses eine foo jedes Mal neu zuzuweisen, was das endgültige Schlüsselwort verletzt .
quelle
final
bindet nur den Verweis auf ein bestimmtes Objekt. Es steht Ihnen frei, den 'Status' dieses Objekts zu ändern, nicht jedoch das Objekt selbst.quelle
Es folgen verschiedene Kontexte, in denen final verwendet wird.
Endvariablen Eine Endvariable kann nur einmal zugewiesen werden. Wenn die Variable eine Referenz ist, bedeutet dies, dass die Variable nicht erneut gebunden werden kann, um auf ein anderes Objekt zu verweisen.
Der endgültigen Variablen kann später ein Wert zugewiesen werden (bei der Deklaration muss kein Wert zugewiesen werden), jedoch nur einmal.
Abschlussklassen Eine Abschlussklasse kann nicht erweitert (vererbt) werden.
Endgültige Methoden Eine endgültige Methode kann nicht von Unterklassen überschrieben werden.
quelle
Ich dachte daran, hier eine aktualisierte und ausführliche Antwort zu schreiben.
final
Schlüsselwort kann an mehreren Stellen verwendet werden.Ein
final class
Mittel , dass keine andere Klasse kann verlängern , dass die letzte Klasse. Wenn Java Run Time ( JRE ) weiß, dass eine Objektreferenz vom Typ einer endgültigen Klasse ist (z. B. F), weiß sie, dass der Wert dieser Referenz nur vom Typ F sein kann.Ex:
Also , wenn es irgendeine Methode des Objekts führt, dass Verfahren nicht benötigt zur Laufzeit aufgelöst werden , um eine Verwendung von virtuellen Tabelle . dh Laufzeitpolymorphismus kann nicht angewendet werden. Die Laufzeit kümmert sich also nicht darum. Dies spart Verarbeitungszeit und verbessert die Leistung.
A
final method
einer Klasse bedeutet, dass eine untergeordnete Klasse, die diese Klasse erweitert, diese endgültige (n) Methode (n) nicht überschreiben kann . Das Laufzeitverhalten in diesem Szenario entspricht also auch dem vorherigen Verhalten, das ich für Klassen erwähnt habe.Wenn oben angegeben wurde
final
, bedeutet dies, dass der Wert bereits finalisiert ist und der Wert daher nicht geändert werden kann .Ex:
Für Felder lokale Parameter
Für Methodenparameter
Dies bedeutet einfach, dass der Wert des
final
Referenzwerts nicht geändert werden kann. dh nur eine Initialisierung ist zulässig. In diesem Szenario werden zur Laufzeit, da JRE weiß, dass Werte nicht geändert werden können, alle diese finalisierten Werte (der endgültigen Referenzen) in den L1-Cache geladen . Weil es nicht braucht , um wieder zu laden immer wieder aus dem Hauptspeicher . Andernfalls wird es in den L2-Cache geladen und von Zeit zu Zeit aus dem Hauptspeicher geladen. Es ist also auch eine Leistungsverbesserung.In allen oben genannten drei Szenarien müssen
final
wir uns keine Sorgen machen , wenn wir das Schlüsselwort nicht an Stellen angegeben haben, die wir verwenden können. Compiler-Optimierungen erledigen dies für uns. Es gibt noch viele andere Dinge, die Compiler-Optimierungen für uns tun. :) :)quelle
Vor allem sind richtig. Wenn Sie nicht möchten, dass andere Unterklassen aus Ihrer Klasse erstellen, deklarieren Sie Ihre Klasse als endgültig. Dann wird es zur Blattebene Ihrer Klassenbaumhierarchie, die niemand weiter erweitern kann. Es ist eine gute Praxis, eine große Klassenhierarchie zu vermeiden.
quelle