2012-01-29 13 views
9

Dlaczego miałbym używać statycznego bloku:Dlaczego używać bloków statycznych zamiast bezpośredniego inicjowania zmiennych instancji?

static { 
    B = 10; 
} 

nad:

Integer B = 10; 

Jakie są zalety/wady jednego nad drugim?

+0

To mniej o odpowiedź i więcej ostrzeżenie ... inicjalizatory statyczne uruchamiane są w metodzie syntetycznej clinit() {class init}, która jest * niejawnie zsynchronizowana *. Dlatego musisz być ostrożny z każdym kodem, który wywołujesz wewnątrz statycznego inicjalizatora, ponieważ aplikacje wielowątkowe mogą powodować impas z ładowania plików klasy! Jeśli chcesz odwołać się do innych klas, których nie kontrolujesz lub nie rozumiesz, możesz użyć abstrakcji dostawcy, aby opóźnić inicjowanie do czasu załadowania klasy ... – Ajax

Odpowiedz

9

Powinieneś używać statycznego bloku inicjalizatora tylko wtedy, gdy jest to konieczne. Na przykład czasami trzeba wykonać kilka kroków, aby obliczyć ostateczną wartość pola. W tym przypadku masz dwie możliwości: napisać metodę, która oblicza wartość i deklarują swoją boiska static final Integer B = calculateB() lub użyj bloku initializer:

static final Integer B; 
static { 
    int temp = ...; 
    ... 
    B = temp; 
} 

w tym przypadku wolę statyczny blok, ponieważ metoda może być mylące (inni programiści mogą próbować go wywołać, chociaż ma on być wywołany tylko raz podczas inicjalizacji).

To samo dotyczy również pól instancji, chociaż normalnie można by uniknąć nietypowego bloku inicjalizacyjnego i po prostu zapisać logikę inicjalizacji dla pól w konstruktorze (co oczywiście nie jest możliwe w przypadku pól statycznych).

4

Inicjalizacja statyczna ma miejsce po załadowaniu klasy.

E.g. byłoby to właściwe miejsce do inicjowania zmiennych członkowskich, które w przeciwnym razie wymagałyby synchronizacji z powodu dostępu przez wiele wątków.

Drugi przypadek mógłby się zdarzyć, gdyby użytkownik wyraźnie zadzwonił do konstruktora.

Sposób użycia jest inny.
E.g. wolisz drugi przypadek leniwego ładowania czegoś (jeśli umieścisz go w statycznych inicjalizatorach, to zawsze będzie ładował się i być może nie będziesz tego chciał - wolisz go leniwie ładować)

+1

Niestety nie jestem pewien, czy rozumiem różnicę? Z pewnością ładowanie klasy jest takie samo jak wywołanie jej konstruktora? –

+3

Nie, absolutnie nie. Na przykład wywołanie metody statycznej na klasie spowoduje jej załadowanie, ale nie uruchomi żadnego konstruktora. – DNA

12

Blok static pozwala pisać bardziej skomplikowane logika inicjalizacji dla atrybutu, natomiast inicjalizacja jednoliniowa ogranicza do pojedynczego wyrażenia.

Należy pamiętać, że bloki inicjalizacji istnieć zarówno instancji i statycznych atrybutów, na przykład ten inicjuje atrybut instancji w czasie konkretyzacji:

private int a; 
{ a = 10; } 

niniejsza jeden inicjuje atrybut statycznego w czasie klasa ładunkowej:

private static int b; 
static { b = 10; } 

Procedura inicjalizacji jest szczegółowo opisana w here, jako część specyfikacji JVM.

2

Najpierw Twoja Integer B wydaje się być niestatyczną zmienną składową i nie można uzyskać do niej dostępu z bloku statycznego. Więc albo oznaczało napisać

//Initialize static field 
static { 
    B = 10; 
} 
static Integer B = 10; 

lub

//Initialize member field 
{ 
    B = 10; 
} 
Integer B = 10; 

W obu przypadkach można go używać do zainicjowania B o wartości, która może spowodować wyjątek lub zrobić coś bardziej skomplikowane bez pisania specjalnej metody w tym.

{ 
    try{ 
     B = thisWillThrowAFileNotFound(); 
    }catch(FileNotFoundException){ 
     B = 10;//Set default 
    } 

} 
2

Właściwie, jeśli masz

private static Integer B = 10; 

Kompilator przełoży się zasadniczo:

private static Integer B; 
static { 
    B = 10; 
} 

Rzecz z bloków statycznych jest to, że można korzystać cały język i nie tylko wyrażenia do przeprowadzenia inicjalizacji. Wyobraź sobie, że trzeba tablicę z bandą wielokrotności 7. Można zrobić:

private static Integer[] array; 
static { 
    array = new Integer[1000]; 
    for (int i = 0; i < 1000; i++) { 
     array[i] = 7 * i; 
    } 
} 

W każdym razie, można również zrobić to w ten sposób:

private static Integer[] array = initArray(); 
private static Integer[] initArray() { 
    Integer[] result = new Integer[1000]; 
    for (int i = 0; i < 1000; i++) { 
     result[i] = 7 * i; 
    } 
    return result; 
} 
Powiązane problemy