Dlaczego statyczne pola nie są inicjowane w czasie?
Poniższy kod drukuje null
raz.
class MyClass {
private static MyClass myClass = new MyClass();
private static final Object obj = new Object();
public MyClass() {
System.out.println(obj);
}
public static void main(String[] args) {}
}
Dlaczego obiekty statyczne nie są inicjowane przed uruchomieniem konstruktora?
Update
Skopiowałem ten przykładowy program bez uwagi, myślałem, że mówimy o 2 polach obiektowych, teraz zobaczyłem, że pierwsze jest polem MyClass.. :/
5 answers
Ponieważ statyki są inicjowane w kolejności podanej w kodzie źródłowym.
Zobacz też:
class MyClass {
private static MyClass myClass = new MyClass();
private static MyClass myClass2 = new MyClass();
public MyClass() {
System.out.println(myClass);
System.out.println(myClass2);
}
}
Które wydrukują:
null
null
myClassObject
null
EDIT
Ok narysujmy to, żeby było bardziej jasne.
- statyki są inicjowane jeden po drugim w kolejności zadeklarowanej w kodzie źródłowym.
- ponieważ pierwsza statyczna jest inicjalizowana przed resztą, podczas jej inicjalizacji pozostałe pola statyczne są null lub domyślne wartości.
- podczas inicjacji drugiej statyki pierwsza statyczna jest poprawna, ale pozostałe są nadal null lub domyślne.
EDIT 2
Jak zauważył Varman, odniesienie do siebie będzie null podczas inicjalizacji. Co ma sens, jeśli się nad tym zastanowić.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 23:46:00
Spróbujmy inaczej to wyjaśnić...
Jest to sekwencja, przez którą przechodzi JVM, gdy po raz pierwszy odwołujesz się do klasy MyClass
.
- załaduj kod bajtowy do pamięci.
- pamięć dla statycznej pamięci jest wyczyszczona (binary zero).
- Zainicjalizuj klasę:
- uruchamia każdy statyczny inicjalizator w kolejności, w jakiej się pojawia, obejmuje to statyczne zmienne i bloki
static { ... }
. - JVM następnie inicjalizuje zmienną statyczną
myClass
na nową instancjaMyClass
.
JVM zwraca uwagę na to, że
MyClass
jest już załadowany (kod bajtowy) i jest w trakcie inicjalizacji, więc pomija inicjalizację. - uruchamia każdy statyczny inicjalizator w kolejności, w jakiej się pojawia, obejmuje to statyczne zmienne i bloki
- Przydziel pamięć na stercie dla obiektu.
- wykonaj konstruktor.
- wypisuje wartość
obj
, która jest nadalnull
(ponieważ nie jest częścią sterty i konstruktora zainicjalizowanych zmiennych). - po zakończeniu konstruktora, wykonaj następny statyczny inicjalizator, który ustawi
obj
na nowy instancjaObject
.
obj
nie będzie null
, ale odniesienie do instancji Object
.Pamiętaj, że Java określa, że zmiennej final
przypisana jest wartość raz. Nie jest tak, że jest gwarantowane, że zostanie przypisana wartość, gdy kod odwołuje się do niego, chyba że zapewnisz, że kod odwołuje się do niego po jego przypisaniu.
Zauważ również, że to wszystko dzieje się w tym samym wątku, który jako pierwszy odwołuje się do klasy. Po drugie, JVM gwarantuje, że inicjalizacja zakończy się, zanim jakikolwiek inny wątek zostanie dozwolone do korzystania z tej klasy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-01 01:24:16
Dzieje się tak dlatego, że Java wykonuje sekcję statyczną w kolejności, w jakiej została zadeklarowana. W Twoim przypadku sekwencja
- new MyClass
- nowy obiekt
Gdy wykonywany jest #1, obj nadal nie jest inicjowany, więc wypisuje null. Spróbuj wykonać następujące czynności, a zobaczysz różnicę:
class MyClass {
private static final Object obj = new Object();
private static MyClass myClass = new MyClass();
public MyClass() {
System.out.println(obj); // will print null once
}
}
Ogólnie rzecz biorąc, lepiej unikać takiej konstrukcji razem. Jeśli próbujesz utworzyć singleton, tak powinien wyglądać ten fragment kodu:
class MyClass {
private static final MyClass myClass = new MyClass();
private Object obj = new Object();
private MyClass() {
System.out.println(obj); // will print null once
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-30 19:02:20
Dzieje się tak dlatego, że statyczne pola inicjowane są w tej samej kolejności, w jakiej zostały zdefiniowane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-30 18:44:08
@ Pirolistic
Ponieważ inicjał pierwszego pola statycznego nie jest w pełni skonstruowany ...wynik jaki otrzymuję to
Null null testInitialize.MyObject @ 70f9f9d8 null
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-02 02:27:15