wtorek, września 15, 2009

Javozagadka ;-)

Popatrzcie na ten kod:
public enum E {
A(E.B);
static final int B = 1;
E(int i) { }
}

Czy ten kod jest prawidłowy czy nie? ;-)

JAVAC z JDK 1.5 i JDK 1.6 go lubią, ale już MyEclipse 7.5 twierdzi, że w 2 linii mamy błąd "Illegal forward reference".
JAVAC nie lubił by tego kodu gdyby wyglądał on tak:
public enum E {
A(B); // <--- nieładnie, próbujemy odwołać się do pola zanim zostało zadeklarowane
static final int B = 1;
E(int i) { }
}


Wydawało mi się, że ten błąd w MyEclipse 7.5 jest spowodowany błędem w Eclipse 3.5, ale wychodzi na to, że to nie to ;-)

Trudno powiedzieć jak to wygląda od strony języka, bo niby A w E jest czymś statycznym i finalnym do zainicjowania czego używamy czegoś co jeszcze mogło nie zostać zainicjalizowane...

Przerobienie tego kodu do takiej postaci:
public enum E {
A(E.A),B(E.A); //
E i;
E(E i) { this.i = i; }

public static void main(String[] args) {
System.out.println(A.i);
System.out.println(B);
}
}

Powoduje, że A inicjalizowane jest przy pomocy null, ale w przypadku naszego pierwszego kodu inicjalizowane jest poprawną wartością...

W ogóle gdy parametr "konstruktora" enuma jest obiektem to wtedy dana wartość enuma dostaje w konstruktorze null, a w przypadku prymitywu wartość ;-) to samo zresztą w przypadku Stringa ;-)

Wygląda więc to tak, że w trakcie ładowania enuma pola są inicjalizowane na wartości trzymane w constant poolu, jeżeli są tam umieszczone, lub na wartości domyślne, następnie inicjalizowane są pola takie jak np. wartości enuma czy wartości pól klasy.
I przez to wydaje się to działać raz w jeden sposób, a raz w drugi ;-)

A wracając do MyEclipse 7.5, nasz projektowy kod w którym użyliśmy takiej konstrukcji jak ta u góry zmieniłem tylko i wyłącznie po to by zaspokoić oczekiwania MyEclipse'a ;-)


Podobne postybeta
Lubię enumy
clone() i Cloneable się mszczą ;-)
.... ku rozproszonej JVM
Przepływ sterowany danymi - A takie Java'owe coś ;-)
Sztuczki tropiciela błędów, part 3 - hackujemy klasy finalne ;-)