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ą?


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 .


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.


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.


Istnieją sposoby odwoływania się do klasy bez jej inicjowania.
Lew Bloch
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.