Kiedy następuje inicjalizacja klasy statycznej?

110

Kiedy są inicjalizowane pola statyczne? Jeśli nigdy nie utworzę instancji klasy, ale mam dostęp do pola statycznego, to czy WSZYSTKIE bloki statyczne i prywatne metody statyczne używane do tworzenia instancji prywatnych pól statycznych są w tej chwili wywoływane (w kolejności)?

A jeśli wywołam metodę statyczną? Czy obsługuje również wszystkie statyczne bloki? Przed metodą?

Tony R.
źródło
Podobnie jest z blokami statycznych inicjatorów: stackoverflow.com/questions/2007666/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

156

Inicjalizacja statyczna klasy zwykle ma miejsce bezpośrednio przed pierwszym z następujących zdarzeń:

  • tworzona jest instancja klasy,
  • wywoływana jest statyczna metoda klasy,
  • przypisane jest pole statyczne klasy,
  • używane jest niestałe pole statyczne lub
  • w przypadku klasy najwyższego poziomu wykonywana jest instrukcja assert zagnieżdżona leksykalnie w klasie 1 .

Zobacz JLS 12.4.1 .

Możliwe jest również wymuszenie inicjalizacji klasy (jeśli jeszcze nie została zainicjowana) przy użyciu Class.forName(fqn, true, classLoader)lub krótkiej formyClass.forName(fqn)


1 - Ostatni punkt znajdował się w JLS dla Java 6 do Java 8, ale najwyraźniej był to błąd specyfikacji. Ostatecznie został poprawiony w Java 9 JLS: patrz źródło .

Stephen C.
źródło
9
Jest jednak pewna pułapka. Prymitywy is Stringsą podstawiane i nie są do nich odwoływane. Jeśli odwołujesz się do class Other { public static final int VAL = 10; }jakiejś klasy MyClass { private int = Other.VAL; }, klasa Othernie zostanie załadowana. Zamiast tego kompilator po prostu podstawi ostatnie pole w czasie kompilacji.
Rafael Winterhalter
6
@RafaelWinterhalter - tak ... to jest stały przypadek pola statycznego.
Stephen C
2
@RafaelWinterhalter, nie jest to prawdą dla wszystkich prymitywów lub Stringzmiennych „statyczny końcowy” , tylko te zainicjowane przez stałe wyrażenie.
Lew Bloch
1
Tak, a pole nie musi nawet być, staticgdy jest to powszechny przypadek.
Rafael Winterhalter
1
To ten sam język programowania. Tak.
Stephen C
14

Pola statyczne są inicjowane podczas „fazy” inicjalizacji ładowania klasy (ładowania, łączenia i inicjalizacji), która obejmuje statyczne inicjatory i inicjalizacje jej pól statycznych. Inicjatory statyczne są wykonywane w kolejności tekstowej zdefiniowanej w klasie.

Rozważmy przykład:

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"
    }
}

Plik Test.b jest drukowany, nullponieważ gdy wywołano element sayHellow zakresie statycznym, zmienna statyczna anie została zainicjowana.

naikus
źródło
6
Ściśle mówiąc, inicjalizacja nie jest „fazą” ładowania klasy. Rzeczywiście, niektóre klasy mogą być ładowane, ale nigdy nie są inicjowane, jeśli aplikacja faktycznie ich nie używa.
Stephen C
@Stephen C Masz rację, użyłem go z braku lepszego określenia, może zacytuję.
naikus
@StephenC czy to oznacza, że ​​podczas ładowania klasy przypisuje pamięć do zmiennych statycznych (i metod), ale te zmienne statyczne nie są inicjowane wartościami podanymi w kodzie? ponieważ tutaj wydaje się, że gdy b-> sayHello () -> a, 'a' jest w pamięci, ale wartość do niego nie jest jeszcze przypisana.
Shabbir Essaji
Zasadniczo tak.
Stephen C
1

Tak, wszystkie statyczne inicjatory są uruchamiane przed pierwszym uzyskaniem dostępu do klasy. Gdyby było inaczej, nazwałbym to błędem.

Nikita Rybak
źródło
Istnieją sposoby odwoływania się do klasy bez jej inicjowania.
Lew Bloch