Soweit ich verstanden habe, wird der "statische Initialisierungsblock" verwendet, um Werte des statischen Feldes festzulegen, wenn dies nicht in einer Zeile möglich ist.
Aber ich verstehe nicht, warum wir dafür einen speziellen Block brauchen. Zum Beispiel deklarieren wir ein Feld als statisch (ohne Wertzuweisung). Schreiben Sie dann mehrere Zeilen des Codes, die einen Wert generieren und dem oben deklarierten statischen Feld einen Wert zuweisen.
Warum brauchen wir diese Zeilen in einem speziellen Block wie : static {...}
?
{...}
vsstatic {...}
. (In diesem Fall hat Jon Skeet Ihre Frage definitiv besser beantwortet)Antworten:
Der nicht statische Block:
Wird jedes Mal aufgerufen, wenn eine Instanz der Klasse erstellt wird. Der statische Block wird nur einmal aufgerufen , wenn die Klasse selbst initialisiert wird, unabhängig davon, wie viele Objekte dieses Typs Sie erstellen.
Beispiel:
Dies druckt:
quelle
Wenn sie nicht in einem statischen Initialisierungsblock wären, wo wären sie? Wie würden Sie eine Variable deklarieren, die nur zum Zwecke der Initialisierung lokal sein sollte, und sie von einem Feld unterscheiden? Wie möchten Sie zum Beispiel schreiben:
Wenn
first
undsecond
nicht in einem Block, würden sie wie Felder aussehen. Wenn sie sich in einem Block ohnestatic
davor befinden würden, würde dies als Instanzinitialisierungsblock anstelle eines statischen Initialisierungsblocks gelten, sodass er einmal pro konstruierter Instanz und nicht einmal insgesamt ausgeführt würde.In diesem speziellen Fall können Sie stattdessen eine statische Methode verwenden:
... aber das funktioniert nicht, wenn es mehrere Variablen gibt, die Sie innerhalb desselben Blocks zuweisen möchten, oder keine (z. B. wenn Sie nur etwas protokollieren oder eine native Bibliothek initialisieren möchten).
quelle
private static int widgets = 0; static{widgets = 2;}
private static int widgets = 0; static{widgets = 2;}
festgestellt, dass die Zuweisung '=' in der richtigen Reihenfolge erfolgt, was bedeutet, dass das zuerst gesetzte '=' zuerst zugewiesen wird. Das obige Beispiel gibt 'Widgets' den Wert 2. (PS wusste nicht, dass Kommentare nur in 5 Minuten bearbeitet werden können ...)Hier ist ein Beispiel:
Der Code in den Abschnitten "statisch" wird zur Ladezeit der Klasse ausgeführt, bevor Instanzen der Klasse erstellt werden (und bevor statische Methoden von einer anderen Stelle aufgerufen werden). Auf diese Weise können Sie sicherstellen, dass alle Klassenressourcen einsatzbereit sind.
Es ist auch möglich, nicht statische Initialisierungsblöcke zu haben. Diese verhalten sich wie Erweiterungen der für die Klasse definierten Konstruktormethoden. Sie sehen genauso aus wie statische Initialisierungsblöcke, außer dass das Schlüsselwort "static" weggelassen wird.
quelle
Dies ist auch nützlich, wenn Sie den Wert eigentlich nichts zuweisen möchten, z. B. wenn Sie eine Klasse zur Laufzeit nur einmal laden .
Z.B
Hey, es gibt noch einen weiteren Vorteil, mit dem Sie Ausnahmen behandeln können. Stellen Sie sich vor, dass
getStuff()
hier einException
was wirklich wirft in einen Fangblock gehört:dann ein
static
ist hier Initialisierer nützlich. Dort können Sie die Ausnahme behandeln.Ein anderes Beispiel ist, danach Dinge zu tun, die während der Zuweisung nicht erledigt werden können:
Um zum Beispiel des JDBC-Treibers zurückzukehren, verwendet jeder anständige JDBC-Treiber selbst auch den
static
Initialisierer, um sich im zu registrierenDriverManager
. Siehe auch diese und diese Antwort.quelle
Ich würde sagen, es
static block
ist nur syntaktischer Zucker. Mitstatic
Block und nichts anderem kann man nichts anfangen.Um einige hier veröffentlichte Beispiele wiederzuverwenden.
Dieser Code kann ohne Verwendung des
static
Initialisierers neu geschrieben werden .Methode 1: Mit
static
Methode 2: Ohne
static
quelle
Es gibt einige tatsächliche Gründe, aus denen es existieren muss:
static final
Mitgliedern, deren Initialisierung möglicherweise eine Ausnahme auslöststatic final
mit berechneten Werten initialisierenBenutzer verwenden
static {}
Blöcke in der Regel als bequeme Methode, um Dinge zu initialisieren, von denen die Klasse auch innerhalb der Laufzeit abhängt - beispielsweise um sicherzustellen, dass eine bestimmte Klasse geladen ist (z. B. JDBC-Treiber). Das kann auf andere Weise geschehen; Die beiden oben genannten Dinge können jedoch nur mit einem Konstrukt wie demstatic {}
Block ausgeführt werden.quelle
Sie können Codebits einmal für eine Klasse ausführen, bevor ein Objekt in den statischen Blöcken erstellt wird.
Z.B
quelle
Es ist ein weit verbreitetes Missverständnis zu glauben, dass ein statischer Block nur Zugriff auf statische Felder hat. Dazu möchte ich im Folgenden einen Teil des Codes zeigen, den ich häufig in realen Projekten verwende (teilweise aus einer anderen Antwort in einem etwas anderen Kontext kopiert ):
Hier wird der Initialisierer verwendet, um einen Index (
ALIAS_MAP
) zu verwalten und eine Reihe von Aliasen wieder dem ursprünglichen Aufzählungstyp zuzuordnen. Es ist als Erweiterung der integrierten valueOf-Methode gedacht, die von sichEnum
selbst bereitgestellt wird .Wie Sie sehen können, greift der statische Initialisierer sogar auf das
private
Feld zualiases
. Es ist wichtig zu verstehen, dass derstatic
Block bereits Zugriff auf dieEnum
Wertinstanzen hat (zENGLISH
. B. ). Dies liegt daran, dass die Reihenfolge der Initialisierung und Ausführung beiEnum
Typen so ist , als ob diestatic private
Felder mit Instanzen initialisiert wurden, bevor diestatic
Blöcke aufgerufen wurden:Enum
Konstanten, die implizite statische Felder sind. Dies erfordert den Enum-Konstruktor und die Instanzblöcke, und die Instanzinitialisierung muss ebenfalls zuerst erfolgen.static
Blockierung und Initialisierung statischer Felder in der Reihenfolge ihres Auftretens.Diese Initialisierung außerhalb der Reihenfolge (Konstruktor vor
static
Block) ist wichtig zu beachten. Es passiert auch, wenn wir statische Felder mit den Instanzen ähnlich einem Singleton initialisieren (Vereinfachungen vorgenommen):Was wir sehen, ist die folgende Ausgabe:
Klar ist, dass die statische Initialisierung tatsächlich vor dem Konstruktor und sogar danach erfolgen kann:
Durch einfachen Zugriff auf Foo in der Hauptmethode wird die Klasse geladen und die statische Initialisierung gestartet. Im Rahmen der statischen Initialisierung rufen wir jedoch erneut die Konstruktoren für die statischen Felder auf. Danach wird die statische Initialisierung fortgesetzt und der aus der Hauptmethode aufgerufene Konstruktor vervollständigt. Ziemlich komplexe Situation, für die ich hoffe, dass wir uns bei normaler Codierung nicht damit befassen müssen.
Weitere Informationen hierzu finden Sie im Buch " Effective Java ".
quelle
aliases
bedeutet nicht, dass der statische Block auf nicht statische Mitglieder zugreifen kann.aliases
Der Zugriff erfolgt über dieLanguage
von der / static /values()
-Methode zurückgegebenen Werte . Wie Sie bereits erwähnt haben, ist die Tatsache, dass die Enum-Variablen zu diesem Zeitpunkt bereits verfügbar sind, das ungewöhnliche Bit - nicht statische Mitglieder regulärer Klassen wären in dieser Situation nicht zugänglich.class Foo { static final Foo Inst1; static final Foo Inst2; static{ Inst1 = new Foo("Inst1"); Inst2 = new Foo("Inst2"); } static { System.out.println("Inst1: " + Inst1.member); System.out.println("Inst2: " + Inst2.member); } private final String member; private Foo(String member){ this.member = member; } }
Der obige Code unterscheidet sich nicht vom Enum-Beispiel und ermöglicht weiterhin den Zugriff auf Instanzvariablen innerhalb des statischen BlocksEnum
. Dies ist der beste Weg, um sicherzustellen, dass wir auf einzelne Instanzen verweisen hier . Und zu Ihren Punkten habe ich mehrere Aktualisierungen vorgenommen.Wenn Ihre statischen Variablen zur Laufzeit festgelegt werden müssen, ist ein
static {...}
Block sehr hilfreich.Zum Beispiel, wenn Sie das statische Element auf einen Wert setzen müssen, der in einer Konfigurationsdatei oder Datenbank gespeichert ist.
Auch nützlich, wenn Sie einem statischen Element Werte hinzufügen möchten,
Map
da Sie diese Werte in der ursprünglichen Elementdeklaration nicht hinzufügen können.quelle
Sie haben also ein statisches Feld (es wird auch als "Klassenvariable" bezeichnet, da es eher zur Klasse als zu einer Instanz der Klasse gehört; mit anderen Worten, es ist eher der Klasse als einem Objekt zugeordnet) und Sie möchten es initialisieren. Wenn Sie also KEINE Instanz dieser Klasse erstellen und dieses statische Feld bearbeiten möchten, können Sie dies auf drei Arten tun:
1- Initialisieren Sie es einfach, wenn Sie die Variable deklarieren:
2- Haben Sie einen statischen Initialisierungsblock:
3- Haben Sie eine Klassenmethode (statische Methode), die auf die Klassenvariable zugreift und diese initialisiert: Dies ist die Alternative zum obigen statischen Block; Sie können eine private statische Methode schreiben:
Warum sollten Sie nun statische Initialisierungsblöcke anstelle statischer Methoden verwenden?
Es liegt wirklich an dem, was Sie in Ihrem Programm brauchen. Sie müssen jedoch wissen, dass der statische Initialisierungsblock einmal aufgerufen wird. Der einzige Vorteil der Klassenmethode besteht darin, dass sie später wiederverwendet werden können, wenn Sie die Klassenvariable neu initialisieren müssen.
Angenommen, Sie haben ein komplexes Array in Ihrem Programm. Sie initialisieren es (mit for z. B. Schleife) und dann ändern sich die Werte in diesem Array im gesamten Programm, aber irgendwann möchten kehren Sie zum Anfangswert zurück). In diesem Fall können Sie die private statische Methode aufrufen. Falls Sie in Ihrem Programm keine Neuinitialisierung der Werte benötigen, können Sie einfach den statischen Block verwenden und benötigen keine statische Methode, da Sie sie später im Programm nicht mehr verwenden werden.
Hinweis: Die statischen Blöcke werden in der Reihenfolge aufgerufen, in der sie im Code erscheinen.
Beispiel 1:
Beispiel 2:
quelle
Als Ergänzung, wie @Pointy sagte
Es soll
System.loadLibrary("I_am_native_library")
in statischen Block hinzufügen .Es wird garantiert, dass keine native Methode aufgerufen wird, bevor die zugehörige Bibliothek in den Speicher geladen wird.
Laut loadLibrary von oracle :
Daher wird das Setzen von System.loadLibrary nicht ganz unerwartet verwendet, um zu vermeiden, dass die Bibliothek mehrmals geladen wird.
quelle
Sie müssen zunächst verstehen, dass Ihre Anwendungsklassen selbst zur
java.class.Class
Laufzeit für Objekte instanziiert werden. In diesem Fall werden Ihre statischen Blöcke ausgeführt. Sie können dies also tatsächlich tun:und es würde "myInt is 1" zur Konsole drucken. Beachten Sie, dass ich keine Klasse instanziiert habe.
quelle
quelle
Der statische Block wird für jede Technologie verwendet, um statische Datenelemente auf dynamische Weise zu initialisieren, oder wir können sagen, dass für die dynamische Initialisierung von statischen Datenelementen statische Blöcke verwendet werden. Für die nicht statische Datenelementinitialisierung haben wir einen Konstruktor, den wir jedoch nicht haben Jeder Ort, an dem wir statische Datenelemente dynamisch initialisieren können
Jetzt wird mein statisches int x dynamisch initialisiert. Bcoz, wenn der Compiler zu Solution.x wechselt, lädt er die Lösungsklasse und den statischen Block beim Laden der Klasse. So können wir dieses statische Datenelement dynamisch initialisieren.
}}
quelle