2013-02-11 13 views
46

Czy ktoś może wyjaśnić wyjście z następującego programu? Myślałem, że konstruktorzy są inicjowani przed zmiennymi instancji. Tak więc oczekiwałem, że wyjście będzie "XZYY".Czy pola inicjalizowane przed uruchomieniem kodu konstruktora w Javie?

class X { 
    Y b = new Y(); 

    X() { 
     System.out.print("X"); 
    } 
} 

class Y { 
    Y() { 
     System.out.print("Y"); 
    } 
} 

public class Z extends X { 
    Y y = new Y(); 

    Z() { 
     System.out.print("Z"); 
    } 

    public static void main(String[] args) { 
     new Z(); 
    } 
} 

Odpowiedz

46

Jeśli spojrzeć na decompiled wersji pliku klasy

class X { 
    Y b; 

    X() { 
     b = new Y(); 
     System.out.print("X"); 
    } 
} 

class Y { 
    Y() { 
     System.out.print("Y"); 
    } 
} 

public class Z extends X { 

    Y y; 

    Z() { 
     y = new Y(); 
     System.out.print("Z"); 
    } 

    public static void main(String args[]) { 
     new Z(); 
    } 
} 

może się okazać, że instancja zmiennej y jest przesuwana wewnątrz konstruktora, więc kolejność wykonywania jest następujący

  1. Zadzwoń do konstruktora z Z
  2. Wywołuje domyślnego konstruktora X
  3. Zostaje wywołana pierwsza linia X konstruktor new Y().
  4. Drukuj Y
  5. Drukuj X
  6. Zaproszenie pierwsza linia w konstruktora Z new Y()
  7. Drukuj Y
  8. druku Z

Wszystkie zmienne instancji są inicjowane za pomocą oświadczenia konstruktora.

+0

Świetne wyjaśnienie @Arun P Johhny +1 dla Ciebie. –

+1

* Inicjalizacja * zmiennej instancji jest przenoszona wewnątrz konstruktora. – EJP

+0

Przynajmniej nie kolejna błędna interpretacja specyfikacji. Jest niekompletny, ale pomaga wyjaśnić, co się dzieje. – YoYo

63

Poprawna kolejność inicjalizacji jest:

  1. Statyczne zmienne incjalizatory statyczne bloki inicjalizacji w celu tekstowej, jeśli klasa nie została wcześniej zainicjowane.
  2. Wywołanie super() w konstruktorze, jawne lub niejawne.
  3. Inicjatory zmiennych instancji i bloki inicjalizacji instancji, w kolejności tekstowej.
  4. Pozostałe ciało konstruktora po super().

Zobacz sekcje §2.17.5-6 of the Java Virtual Machine Specification.

+0

404 link niedostępny. –

+0

Link do JLS dla Java 8: http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5 – azurefrog

+0

A także źle - zobacz mój komentarz do @ ÓscarLópez z tym samym kwestia. Zauważ, że 'static' nie jest po prostu częścią sekcji dokumentacji, którą się powołujesz. – YoYo

-3

sekwencji inicjalizacji, jest określony w JLS 12,5:

1.First pamięć jest przeznaczona dla nowego obiektu

2.Then wszystkie zmienne przykład w obiekcie (w tym te zdefiniowane w tej klasie i wszystkie jego nadklasy) zostały zainicjowane zgodnie z ich domyślnymi wartościami:

3. Ostatecznie wywoływany jest konstruktor.

https://stackoverflow.com/questions/26552799/which-run-first-default-values-for-instance-variables-or-super-constructors

+0

Pytanie nie dotyczy wartości domyślnych. – EJP

+0

Wszystkie błędne interpretacje specyfikacji. – YoYo

0

Aby wyjaśnić nieporozumienia ze statycznym - Ja po prostu odwołać się do tego małego kawałka kodu:

public class Foo { 
    { System.out.println("Instance Block 1"); } 
    static { System.out.println("Static Block 1"); } 
    public static final Foo FOO = new Foo(); 
    { System.out.println("Instance Block 2"); } 
    static { System.out.println("Static Block 2 (Weird!!)"); } 
    public Foo() { System.out.println("Constructor"); } 
    static public void main(String p[]) { 
    System.out.println("In Main"); 
    new Foo(); 
    } 
} 

Niespodzianka jest, że wyjście jest następująca:

Static Block 1 
Instance Block 1 
Instance Block 2 
Constructor 
Static Block 2 (Weird!!) 
In Main 
Instance Block 1 
Instance Block 2 
Constructor 

Zauważ, że mamy static {}, która nazywa się po dwie instancji {}. dzieje się tak dlatego, że po raz pierwszy konstruktor jest wywoływany w środku, wrzucając kolejność wykonywania.

Odkryłem to podczas pracy nad tą odpowiedzią - https://stackoverflow.com/a/30837385/744133.

Zasadniczo możemy obserwować tak się stało:

  1. czasie po raz pierwszy obiekt jest zainicjowany, Inicjalizuj bieżący obiekt zarówno statyczne i instancji inicjalizacji przemieszane na podstawie kolejności występowania

  2. Dla wszystkich przy kolejnych inicjalizacjach, inicjowanie instancji odbywa się tylko w kolejności występowania, ponieważ inicjalizacja statyczna już się zdarzyła.

Muszę zbadać, w jaki sposób połączenie dziedziczenia, zarówno jawne, jak i niejawne, połączenia do super i to wpłynie na to i zaktualizuje wyniki. Prawdopodobnie byłby podobny do innych dostarczonych odpowiedzi, z wyjątkiem tego, że pomylili się ze statyczną inicjalizacją.

Powiązane problemy