Wann findet die statische Klasseninitialisierung statt?

110

Wann werden statische Felder initialisiert? Wenn ich nie eine Klasse instanziiere, aber auf ein statisches Feld zugreife, werden ALLE statischen Blöcke und privaten statischen Methoden, die zum Instanziieren privater statischer Felder verwendet werden, zu diesem Zeitpunkt (in der Reihenfolge) aufgerufen?

Was ist, wenn ich eine statische Methode aufrufe? Läuft es auch alle statischen Blöcke? Vor der Methode?

Tony R.
quelle
Ähnliches gilt für statische Initialisierungsblöcke: stackoverflow.com/questions/2007666/…
Ciro Santilli 法轮功 冠状 病 六四 事件 23

Antworten:

156

Die statische Initialisierung einer Klasse erfolgt normalerweise unmittelbar vor dem ersten Auftreten eines der folgenden Ereignisse:

  • eine Instanz der Klasse wird erstellt,
  • Eine statische Methode der Klasse wird aufgerufen.
  • ein statisches Feld der Klasse wird zugewiesen,
  • ein nicht konstantes statisches Feld wird verwendet, oder
  • Für eine Klasse der obersten Ebene wird eine in der Klasse lexikalisch verschachtelte Assert-Anweisung ausgeführt 1 .

Siehe JLS 12.4.1 .

Es ist auch möglich, eine Klasse mithilfe Class.forName(fqn, true, classLoader)der Kurzform zur Initialisierung zu zwingen (sofern sie noch nicht initialisiert wurde)Class.forName(fqn)


1 - Der letzte Aufzählungspunkt war im JLS für Java 6 bis Java 8 vorhanden, aber es war anscheinend ein Fehler in der Spezifikation. Es wurde schließlich in Java 9 JLS korrigiert: siehe Quelle .

Stephen C.
quelle
9
Es gibt jedoch eine häufige Gefahr. Primitive und Strings werden ersetzt und nicht referenziert. Wenn Sie auf eine class Other { public static final int VAL = 10; }aus einer Klasse verweisen MyClass { private int = Other.VAL; }, wird die Klasse Othernicht geladen. Stattdessen ersetzt der Compiler einfach das letzte Feld zur Kompilierungszeit.
Rafael Winterhalter
6
@ RafaelWinterhalter - ja ... das ist der konstante statische Feldfall .
Stephen C
2
@RafaelWinterhalter, dies gilt nicht für alle 'statischen endgültigen' Grundelemente oder StringVariablen, sondern nur für diejenigen, die durch einen konstanten Ausdruck initialisiert wurden.
Lew Bloch
1
Ja, und das Feld muss nicht einmal sein, staticsolange dies üblich ist.
Rafael Winterhalter
1
Es ist dieselbe Programmiersprache. Ja.
Stephen C
14

Statische Felder werden während der " Initialisierungsphase " des Ladens der Klasse (Laden, Verknüpfen und Initialisieren) initialisiert, die statische Initialisierer und Initialisierungen ihrer statischen Felder enthält. Die statischen Initialisierer werden in einer in der Klasse definierten Textreihenfolge ausgeführt.

Betrachten Sie das Beispiel:

public class Test {

   static String sayHello()  {
      return a;
   }

   static String b = sayHello(); // a static method is called to assign value to b.
                                 // but its a has not been initialized yet.

   static String a = "hello";

   static String c = sayHello(); // assignes "hello" to variable c

    public static void main(String[] arg) throws Throwable {
         System.out.println(Test.b); // prints null
         System.out.println(Test.sayHello()); // prints "hello"
    }
}

Die Test.b wird gedruckt, nullda beim Aufrufen sayHellovon im statischen Bereich die statische Variable anicht initialisiert wurde.

Naikus
quelle
6
Genau genommen ist die Initialisierung keine "Phase" des Klassenladens. In der Tat werden einige Klassen möglicherweise geladen, aber nie initialisiert, wenn die Anwendung sie nicht tatsächlich verwendet.
Stephen C
@ Stephen C Sie haben Recht, ich habe es aus Mangel an einem besseren Begriff verwendet, vielleicht zitiere ich es.
Naikus
@StephenC bedeutet dies, dass beim Laden der Klasse statischen Variablen (& Methoden) Speicher zugewiesen wird, diese statischen Variablen jedoch nicht mit den im Code angegebenen Werten initialisiert werden? denn hier scheint es, wenn b-> sayHello () -> a, 'a' im Speicher ist, aber der Wert dafür ist noch nicht zugewiesen.
Shabbir Essaji
Grundsätzlich ja.
Stephen C
1

Ja, alle statischen Initialisierer werden ausgeführt, bevor Sie zum ersten Mal auf die Klasse zugreifen. Wenn es anders wäre, würde ich es einen Fehler nennen.

Nikita Rybak
quelle
Es gibt Möglichkeiten, auf eine Klasse zu verweisen, ohne sie zu initialisieren.
Lew Bloch