2014-06-11 27 views
5

Po prostu próbowałem ustawić zmienną, pokazując mi, że super konstruktor został zakończony bez marnowania mojego kodu. Więc przypomniałem sobie, jak zainicjowano zmienne klasy; po super konstruktorze, ale przed konstruktorem klasy. Ale jest coś dziwnego, jeśli spojrzeć na ten przykład:Różnica między inicjalizacją ostatniej klasy zmiennej

public class Init { 

    public Init() { 
     System.out.println("Init instance of " + this.getClass().getSimpleName()); 
     System.out.println("syso Init:"); 
     this.syso(false); 
    } 

    protected void syso(boolean childCall) { 
     System.out.println("should not be printed because the method is overwitten"); 
    } 

    public static class Child extends Init { 

     private final boolean finalTrueA = true; 
     private final boolean finalTrueB; 
     private final boolean finalTrueC; 

     private boolean nonFinalTrueA = true; 
     private boolean nonFinalTrueB; 
     private boolean nonFinalTrueC; 

     { 
      this.finalTrueB = true; 
      this.nonFinalTrueB = true; 
     } 

     public Child() { 
      super(); 
      this.finalTrueC = true; 
      this.nonFinalTrueC = true; 

      System.out.println("\n\nsyso Child:"); 
      this.syso(true); 
     } 

     @Override 
     protected void syso(boolean childCall) { 
      System.out.println("finalTrueA " + this.finalTrueA + " should be " + childCall); 
      System.out.println("finalTrueB " + this.finalTrueB + " should be " + childCall); 
      System.out.println("finalTrueC " + this.finalTrueC + " should be " + childCall); 

      System.out.println(); 

      System.out.println("nonFinalTrueA " + this.nonFinalTrueA + " should be " + childCall); 
      System.out.println("nonFinalTrueB " + this.nonFinalTrueB + " should be " + childCall); 
      System.out.println("nonFinalTrueC " + this.nonFinalTrueC + " should be " + childCall); 
     } 
    } 

    public static void main(String[] args) { 
     @SuppressWarnings("unused") 
     Child child = new Child(); 
    } 

} 

który ma następujący wynik:

Init instance of Child 
syso Init: 
finalTrueA true should be false // <-- why?????????? 
finalTrueB false should be false 
finalTrueC false should be false 

nonFinalTrueA false should be false 
nonFinalTrueB false should be false 
nonFinalTrueC false should be false 


syso Child: 
finalTrueA true should be true 
finalTrueB true should be true 
finalTrueC true should be true 

nonFinalTrueA true should be true 
nonFinalTrueB true should be true 
nonFinalTrueC true should be true 

Ten efekt można zaobserwować na wyjściu Zaćmienie jak również na prowadzenie klasę javac. Ale debugger eclipse pokazuje poprawną wartość finalTrueA w obrębie super konstruktora wywołania metody syso.

Moje pytanie: czy ten efekt jest prawidłowy, że różne inicjowanie powoduje różne zachowanie pól statycznych i jest to błąd debuggera Eclipse, czy to zachowanie jest nieprawidłowe i jest to błąd java ???

+0

Interesujące. Wygląda na to, że ma to wpływ tylko na pola "final", które mają inicjator używający wartości stałej w czasie kompilacji. –

+0

To zachowanie jest poprawne, ale nie każdy programista jest tego świadomy. – Holger

Odpowiedz

1

Każdy final zmienną, której jest bezpośrednio przyporządkowany stałej kompilacji i posiada pierwotną lub String typu jest stała w czasie kompilacji jak również i jej wartość będzie wstawiane czasie kompilacji stosowane w kontekście wyrażenie . Odnosi się to do zmiennych , nie tylko static. Rozważmy następujący (prawidłowy) kod:

public static void main(String[] args) 
{ 
    final int zero=0, one=zero+1, two=one+one, three=two+one; 
    switch(args.length) 
    { 
    case zero: System.out.println("no args"); break; 
    case one: System.out.println("one arg"); break; 
    case two: System.out.println("two args"); break; 
    case three: System.out.println("three args"); 
    } 
} 

tu zmiennych lokalnych zero, one, two i three są w czasie kompilacji stałych, a więc wolno nawet jak switch case etykiet ...

W ty przypadku wartość z this.finalTrueA zaznaczonym podczas kompilacji, a zatem będzie true nawet po wywołaniu z super-konstruktora.

0

Wszystkie zmienne należy przypisać podczas kompilacji. Albo przez static initializer lub in the constructor lub w samej klasie.

Zobacz wyciąg z jls

It is a compile-time error if a blank final (§4.12.4) class variable is not definitely 
assigned (§16.8) by a static initializer (§8.7) of the class in which it is declared. 

A blank final instance variable must be definitely assigned (§16.9) at the end of every 
constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs 

opiera się na tym, zmienna finalTrueA jest ustawiony na true w czasie samej kompilacji i to dlaczego widzisz true.