Zauważyłem różnicę w zachowaniu automatycznego rozpakowywania między Java SE 6 i Java SE 7. Zastanawiam się, dlaczego tak jest, ponieważ nie mogę znaleźć żadnej dokumentacji dotyczącej zmian w tym zachowaniu między tymi dwiema wersjami.
Oto prosty przykład:
Object[] objs = new Object[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];
Kompiluje się dobrze z javac z Java SE 7. Jeśli jednak podam kompilatorowi argument „-source 1.6”, w ostatnim wierszu pojawi się błąd:
inconvertible types
found : java.lang.Object
required: int
Próbowałem pobrać Java SE 6 do kompilacji z natywnym kompilatorem w wersji 6 (bez żadnej opcji -source). Zgadza się i daje ten sam błąd co powyżej.
Więc co daje? Po dalszych eksperymentach wydaje się, że rozpakowanie w Javie 6 może tylko rozpakować wartości, które wyraźnie (w czasie kompilacji) są typu pudełkowego. Na przykład działa to w obu wersjach:
Integer[] objs = new Integer[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];
Wygląda więc na to, że między Javą 6 a 7 funkcja rozpakowywania została ulepszona, dzięki czemu może rzucać i rozpakowywać typy obiektów za jednym zamachem, bez wiedzy (w czasie kompilacji), że wartość jest odpowiedniego typu pudełkowego. Jednak czytając specyfikację języka Java lub posty na blogu, które zostały napisane w czasie, gdy pojawiła się Java 7, nie widzę żadnej zmiany w tej kwestii, więc zastanawiam się, na czym ta zmiana polega i jak nazywa się ta „funkcja” ?
Ciekawostka: w związku z tą zmianą możliwe jest wywołanie „niewłaściwego” unboxingu:
Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];
Kompiluje się dobrze, ale daje ClassCastException w czasie wykonywania.
Jakieś wzmianki na ten temat?
Integer obj = new Integer(2); int x = (int)obj;
: działa na Javie 7, wyświetla błąd w Javie 6.Odpowiedzi:
Wygląda na to, że język w sekcji 5.5 Casting Conversion of Java 7 JLS został zaktualizowany w porównaniu z tą samą sekcją w Java 5/6 JLS , prawdopodobnie w celu wyjaśnienia dozwolonych konwersji.
Mówi Java 7 JLS
Java 5/6:
Java 7 JLS zawiera również tabelę (tabela 5.1) dozwolonych konwersji (ta tabela nie jest uwzględniona w Java 5/6 JLS) z typów referencyjnych na prymitywy. To jawnie wymienia rzuty z Object na prymitywy jako zawężającą konwersję referencyjną z rozpakowywaniem.
Powód jest wyjaśniony w tym e-mailu :
źródło
Masz rację; mówiąc prościej:
Działa to w Javie 7, ale powoduje błąd kompilacji w Javie 6 i starszych. Co dziwne, ta funkcja nie jest wyraźnie udokumentowana; na przykład nie ma o tym mowy tutaj . Dyskusyjne jest, jeśli jest to nowa funkcja lub poprawka błędu (lub nowy błąd?). Zobacz kilka powiązanych informacji i dyskusji . Konsensus wydaje się wskazywać na niejednoznaczność w oryginalnej specyfikacji, która doprowadziła do nieco niepoprawnej / niespójnej implementacji w Javie 5/6, która została naprawiona w 7, ponieważ była krytyczna dla implementacji JSR 292 (Dynamically Typed Languages).
Autoboxing w Javie ma teraz więcej pułapek i niespodzianek. Na przykład
będzie się kompilować, ale zakończy się niepowodzeniem (z
ClassCastException
) w czasie wykonywania. Zamiast tego zadziała:long x = (long)(int)obj;
źródło