2012-01-12 8 views
6

Wczoraj natknąłem się na interesujący problem i mimo że poprawka była dość prosta, nadal jestem trochę nieostrożny w kwestii "dlaczego".Dlaczego obiekty członkowskie inicjowane są po konstruktorze superklasy?

Mam klasę, która ma prywatną zmienną składową, która jest przypisana, gdy jest tworzona, jednak jeśli jest używana w abstrakcyjnej funkcji, która jest wywoływana przez konstruktor superklasy, zmienna nie ma wartości. Rozwiązanie problemu było dość proste, po prostu musiałem zadeklarować zmienną jako static i została ona poprawnie przypisana. Niektóre kodu do zilustrowania problemu:

class Foo extends BaseClass 
{ 
    private final String bar = "fooBar!"; 
    public Foo() 
    { 
     super(); 
    } 

    @Override 
    public void initialize() 
    { 
     System.out.println(bar); 
    } 
} 

a klasa podstawowa:

abstract class BaseClass 
{ 
    public BaseClass() 
    { 
     initialize(); 
    } 

    public abstract void initialize(); 
} 

W tym przykładzie, kiedy nazywamy new Foo(); to będzie wyjście (null) zamiast oczekiwanego foobar!

Ponieważ powstaje obiekt typu Foo, czy jego członkowie nie powinni być przydzieleni i przydzieleni przed wywołaniem jego konstruktora (iw konsekwencji jego super klasy)? Czy jest to określone gdzieś w języku Java lub czy jest to specyficzne JVM?

Dzięki za wszelkie informacje!

+2

Uważaj na metody wywoływania podklas od ctor klasy nadrzędnej. –

+0

Kod faktycznie wyświetla fooBar! ponieważ zmienna 'bar' jest ostateczna, co czyni ją stałą kompilującą. Bez "final" wydrukowałoby zero. – x22

+0

@ x22 To właściwie niepoprawne, a to, co doprowadziło do zbadania tej sytuacji - wierzyłem w to samo, kiedy ja to napisałem. –

Odpowiedz

7

Przypisanie bar = "fooBar!"; jest wstawione do konstruktora podczas kompilacji.

Konstruktor nadklasy działa pod konstruktorem podklasy before, więc byłoby naturalne, że instrukcja zostanie wykonana później.

Ogólnie rzecz biorąc, to bad practice wywoływanie możliwych do zastąpienia metod z konstruktora.

+0

Awesome, dzięki za link, pomaga bandzie! –

1

Jest zdefiniowany przez specyfikację języka Java. Zmiana na statyczną prawie nigdy nie będzie możliwa do zaakceptowania w realnej sytuacji.

Zobacz JLS 4.12.5 Initial Values of Variables i JLS 8.3.2 Initialization of Fields

Ogólnie rzecz biorąc, jest złą praktyką zadzwonić nieostatecznej metody z konstruktora. Powodem jest to, że mógł (i jeśli metoda jest abstrakcyjna, to zdecydowanie robi) metoda wywołania w klasie, która nie została jeszcze zainicjowana: Po wykonaniu new Foo() inicjator (konstruktor) BaseClass otrzymuje nazwę przed konstruktorem Foo, więc Foo.initialize zasadniczo działa na obiekcie, który nie został jeszcze w pełni skonstruowany.

Powiązane problemy