Zastanawiam się, kiedy zmienne statyczne są inicjowane do wartości domyślnych. Czy to prawda, że po załadowaniu klasy tworzone są (przydzielane) zmienne statyczne, a następnie wykonywane są inicjatory statyczne i inicjalizacje w deklaracjach? W którym momencie podano wartości domyślne? Prowadzi to do problemu odniesienia w przód.
Prosimy również o wyjaśnienie tego w odniesieniu do pytania zadanego w sekcji Dlaczego pola statyczne nie są inicjowane na czas? a zwłaszcza odpowiedź udzielona przez Kevina Brocka na tej samej stronie. Nie rozumiem trzeciego punktu.
java
static
initialization
Ankit
źródło
źródło
Odpowiedzi:
Z See Java Static Variable Methods :
Zmienne instancji i klasy (statyczne) są automatycznie inicjowane do standardowych wartości domyślnych, jeśli nie uda się ich celowo zainicjować. Chociaż zmienne lokalne nie są inicjowane automatycznie, nie można skompilować programu, który nie może zainicjować zmiennej lokalnej ani przypisać wartości do tej zmiennej lokalnej przed jej użyciem.
Kompilator w rzeczywistości tworzy wewnętrzną procedurę inicjalizacji pojedynczej klasy, która łączy wszystkie statyczne inicjatory zmiennych i wszystkie statyczne bloki inicjatora kodu, w kolejności, w jakiej pojawiają się w deklaracji klasy. Ta pojedyncza procedura inicjalizacji jest uruchamiana automatycznie, tylko jeden raz, podczas pierwszego ładowania klasy.
W przypadku klas wewnętrznych nie mogą mieć pól statycznych
Zobacz JLS 8.1.3 Klasy wewnętrzne i instancje zamykające
final
pola w Javie mogą być inicjowane niezależnie od miejsca ich deklaracji, jednak nie może to mieć zastosowania dostatic final
pól. Zobacz poniższy przykład.final class Demo { private final int x; private static final int z; //must be initialized here. static { z = 10; //It can be initialized here. } public Demo(int x) { this.x=x; //This is possible. //z=15; compiler-error - can not assign a value to a final variable z } }
To dlatego, że istnieje tylko jedna kopia ze
static
zmiennych związanych z typem, zamiast jednego związanego z każdej instancji typem ze zmiennych instancji, a jeśli staramy się zainicjowaćz
typustatic final
wewnątrz konstruktora, będzie próbował ponownie zainicjowaćstatic final
pole typuz
ponieważ konstruktor jest uruchamiany na każdej instancji klasy, która nie może wystąpić wfinal
polach statycznych .źródło
In case of static inner classes, they can not have static fields
wygląda na literówkę. Klasy wewnętrzne są niestatyczne.Widzieć:
W szczególności ta ostatnia zapewnia szczegółowe kroki inicjalizacji, które określają, kiedy zmienne statyczne są inicjowane iw jakiej kolejności (z zastrzeżeniem, że
final
zmienne klas i pola interfejsu, które są stałymi czasu kompilacji, są inicjowane jako pierwsze).Nie jestem pewien, jakie jest Twoje konkretne pytanie dotyczące punktu 3 (zakładając, że masz na myśli ten zagnieżdżony?). Szczegółowa sekwencja stwierdza, że będzie to rekurencyjne żądanie inicjalizacji, więc inicjalizacja będzie kontynuowana.
źródło
Pola statyczne są inicjowane, gdy klasa jest ładowana przez program ładujący klasy. W tym momencie przypisywane są wartości domyślne. Odbywa się to w kolejności, w jakiej pojawiają się w kodzie źródłowym.
źródło
Kolejność inicjalizacji:
Szczegóły tego procesu są wyjaśnione w dokumencie specyfikacji JVM .
źródło
zmienna statyczna
źródło
Zaczynając od kodu z drugiego pytania:
class MyClass { private static MyClass myClass = new MyClass(); private static final Object obj = new Object(); public MyClass() { System.out.println(obj); // will print null once } }
Odwołanie do tej klasy rozpocznie inicjalizację. Najpierw klasa zostanie oznaczona jako zainicjowana. Następnie pierwsze pole statyczne zostanie zainicjowane nową instancją MyClass (). Zauważ, że myClass natychmiast otrzymuje odwołanie do pustej instancji MyClass. Przestrzeń jest tam, ale wszystkie wartości są zerowe. Konstruktor jest teraz wykonywany i drukuje
obj
, co jest wartością null.Wracając do inicjalizacji klasy:
obj
odnosi się do nowego rzeczywistego obiektu i gotowe.Jeśli zostało to wyłączone przez instrukcję, taką jak:
MyClass mc = new MyClass();
miejsce na nową instancję MyClass jest ponownie przydzielane (i umieszczane jest odniesieniemc
). Konstruktor jest ponownie wykonywany i ponownie drukujeobj
, co teraz nie jest null.Prawdziwa sztuczka polega na tym, że kiedy używasz
new
, as inWhatEverItIs weii = new WhatEverItIs( p1, p2 );
weii
natychmiast otrzymuje odniesienie do odrobiny zerowej pamięci. JVM przejdzie następnie do zainicjowania wartości i uruchomienia konstruktora. Ale jeśli w jakiś sposób odwołujesz sięweii
do niego, zanim to zrobi - na przykład odwołując się do niego z innego wątku lub lub przez odwołanie z inicjalizacji klasy - patrzysz na instancję klasy wypełnioną wartościami null.źródło
Zmienną statyczną można zainicjować na trzy następujące sposoby, a następnie wybierz dowolny, który Ci się podoba
lub możesz to zrobić, tworząc blok statyczny, np .:
static { // whatever code is needed for initialization goes here }
Istnieje alternatywa dla bloków statycznych - możesz napisać prywatną metodę statyczną
class name { public static varType myVar = initializeVar(); private static varType initializeVar() { // initialization code goes here } }
źródło