Wann wird der statische Block einer Klasse ausgeführt?

73

Ich habe 2 Gläser, nennen wir sie a.jar und b.jar.

b.jar hängt von a.jar ab.

In a.jar habe ich eine Klasse definiert, nennen wir sie StaticClass. In der StaticClass habe ich einen statischen Block definiert und eine Methode namens "init" aufgerufen:

public class StaticClass {
  static {
    init();
  } 

  public void static init () {
    // do some initialization here
  }
}

in b.jar habe ich ein main, also erwarte ich im main, dass die init () -Methode aufgerufen wurde, aber eigentlich nicht. Ich vermute, das liegt daran, dass die StaticClass nicht von der JVM geladen wurde, könnte mir jemand sagen

  1. Ist meine Schlussfolgerung richtig?
  2. Was veranlasst das JVM, eine Klasse zu laden?
  3. Wie kann ich den statischen Block automatisch ausführen lassen?

Vielen Dank

Leon
quelle
3
Sie müssten Ihre StaticClass irgendwo verwenden, damit sie geladen und initialisiert wird.
Kris
3
Es sieht so aus, als würde dies Ihre Frage beantworten.
Andreas Baus
Mögliches Duplikat von: stackoverflow.com/questions/2007666/…
Ciro Santilli 法轮功 冠状 病 六四 事件 12

Antworten:

94

Ja, du hast recht. Statische Initialisierungsblöcke werden ausgeführt, wenn der JVM (Class Loader - um genau zu sein) geladen wird StaticClass(was beim ersten Referenzieren im Code der Fall ist).

Sie können das Aufrufen dieser Methode erzwingen, indem Sie explizit aufrufen. Dies StaticClass.init()ist der Verwendung der JVM vorzuziehen.

Sie können auch versuchen Class.forName(String), die JVM zu zwingen, die Klasse zu laden und ihre statischen Blöcke aufzurufen.

ŁukaszBachman
quelle
"was auftritt, wenn es zum ersten Mal im Code referenziert wird" - nicht immer. Der Zugriff auf einen statischen Grundtyp scheint die statischen Blöcke nicht auszulösen.
7
"Statische Initialisierungsblöcke werden ausgeführt, wenn die JVM StaticClass lädt. --- Falsch, das Laden von Klassen unterscheidet sich von der Klasseninitialisierung.
Marko Topolnik
4
"Dies tritt auf, wenn es zum ersten Mal im Code referenziert wird" --- falsch, die Implementierung kann frei entscheiden, wann die Klasse geladen werden soll. Das Referenzieren der Klasse ist nur die Frist, bis zu der sie definitiv geladen werden muss.
Marko Topolnik
1
@ MarkoTopolnik ist richtig. "Statische Initialisierungsblöcke werden ausgeführt, wenn die JVM StaticClass lädt" ist eine falsche Anweisung. statische Blöcke werden während der Klasseninitialisierung ausgeführt. "was der JVM vorzuziehen ist" ist eine weitere verwirrende Aussage. Im Fall von StaticClass.init (), einem statischen Methodenaufruf, hat dies nichts mit "Verlassen" zu tun.
Shafin Mahmud
@hthserhs Öffentliche statische endgültige Grundelementtypen und Zeichenfolgen werden während eingefügt javac. Daher gibt es vom Standpunkt von JVM aus keinen wirklichen "Zugang". Dadurch ist das Verhalten verständlich. Ich möchte nur einen Kontext hinzufügen. Was Sie gesagt haben, ist sicherlich richtig.
Haozhun
7

Ja, Sie haben Recht, da Sie Ihr nicht verwenden StaticClass, wird es nicht von der VM geladen und daher init()nie ausgeführt.

Bei Ihrer zweiten Frage müssen Sie wahrscheinlich den harten Weg gehen und alle verfügbaren Klassen scannen und laden.

https://stackoverflow.com/a/3223019/393657

Stryba
quelle
+1 für den Hinweis, alle Klassen zu scannen und automatisch zu initialisieren. Es kann hilfreich sein, eine Markierungsschnittstelle / Annotation für die Klassen zu verwenden, deren statischer Initialisierer automatisch ausgeführt werden soll (oder eine andere definierte statische Methode). Wie im verlinkten Thread gesagt: Google Reflections ist möglicherweise eine Möglichkeit, dies ohne großen Aufwand zu tun.
Thomas
5

Zunächst unterscheidet sich das Laden von Klassen von der Klasseninitialisierung. Für alle, die nach Erklärungen aus der Java-Sprachspezifikation suchen, wann ein statischer Block ausgeführt wird - hier ist er.

Der JLS §8.7 sagt, dass:

Ein in einer Klasse deklarierter statischer Initialisierer wird ausgeführt, wenn die Klasse initialisiert wird (§12.4.2).

Was bedeutet die Initialisierung? Wir verweisen auf JLS §12.4.2 . Dies beschreibt ein detailliertes Initialisierungsverfahren. Punkt JLS §12.4.1 könnte hier jedoch angemessener sein. Es steht dass :

Eine Klasse oder ein Schnittstellentyp T wird unmittelbar vor dem ersten Auftreten einer der folgenden Aktionen initialisiert:
  • T ist eine Klasse und eine Instanz von T wird erstellt.
  • T ist eine Klasse und eine von T deklarierte statische Methode wird aufgerufen.
  • Ein von T deklariertes statisches Feld wird zugewiesen.
  • Ein von T deklariertes statisches Feld wird verwendet und das Feld ist keine konstante Variable (§4.12.4).
  • T ist eine Klasse der obersten Ebene (§7.6), und eine in T (§8.1.3) lexikalisch verschachtelte Assert-Anweisung (§14.10) wird ausgeführt.
  • Damit der statische Initialisierungsblock automatisch ausgeführt wird, müssen Sie eine dieser Optionen erzwingen.

    michalk
    quelle
    Ich frage mich, ob wir davon ausgehen können, dass: class initialisiert wird, wenn in einem bereits laufenden Code namentlich darauf verwiesen wird.
    Pawel Dubiel
    4

    Sie haben Recht, der einfachste Weg ist, auf die Klasse zuzugreifen, zum Beispiel a

    StaticClass.class.newInstance();

    Oder etwas in dieser Hinsicht in Ihrer Hauptmethode. Dadurch wird sichergestellt, dass die Klasse vom Klassenladeprogramm geladen wird.

    Hiery Nomus
    quelle
    3

    Der statische Code wird ausgeführt, wenn auf Ihre Klasse ( StaticClassglaube ich) verwiesen wird.

    Daher sollte es ausgeführt werden, wenn Sie eine neue Instanz von erstellen StaticClassoder eine der statischen Methoden aufrufen .

    C. Champagner
    quelle
    3

    Der statische Block wird ausgeführt, wenn eine geladene Klasse zuerst initialisiert oder referenziert wird. Das Laden einer Klasse bedeutet nicht, dass die Klasse initialisiert werden soll. Das Laden der JVM-Klasse ist ein separates Problem.

    Shafin Mahmud
    quelle
    0

    Ja, der statische Initialisierer wird ausgeführt, wenn die Klasse geladen wird. Dies tritt normalerweise auf, wenn Sie zum ersten Mal im Klassenladekontext auf die Klasse zugreifen.

    Thomas
    quelle
    0

    In der Hauptmethodenklasse b.jar sollte diese StaticClass erweitert werden, dann werden automatisch der statische Block und init () aufgerufen

    Santoshbharat
    quelle
    -2

    Weitere hinzufügen:

    Der statische Block wird ausgeführt, wenn die JVM-Ladeklasse verwendet wird.

    Hier in Ihrem Beispiel können Sie die init()Methode von StaticClassdurch Aufrufen der Klasse aufrufen

    wie StaticClass staticClass = new StaticClass ();

    oder

    StaticClass.class.newInstance(); das ist mehr bevorzugt

    AhsanAli Nandoliya
    quelle
    3
    "Das ist besser" warum?
    Marquis von Lorne