Różnice w auto-unboxingu pomiędzy Java 6 vs Java 7

Zauważyłem różnicę w zachowaniu automatycznego rozpakowywania pomiędzy Javą SE 6 i Javą SE 7. Zastanawiam się dlaczego tak jest, ponieważ nie mogę znaleźć żadnej dokumentacji zmian w tym zachowaniu między tymi dwoma wersjami.

Oto prosty przykład:

Object[] objs = new Object[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

To dobrze kompiluje się z javac z Java SE 7. Jeśli jednak podam kompilatorowi argument "- source 1.6", w ostatniej linii pojawi się błąd:

inconvertible types
found   : java.lang.Object
required: int

Próbowałem pobrać Java SE 6 do kompilacji z natywną wersją 6 kompilator (bez opcji-source). Zgadza się i daje taki sam błąd jak powyżej.

Więc co daje? Z dalszych eksperymentów wydaje się, że unboxing w Javie 6 może rozpakowywać tylko wartości, które wyraźnie (w czasie kompilacji) są typu boxed. 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 pomiędzy Javą 6 i 7 funkcja unboxingu została ulepszona tak, że mogła rzucać i rozpakowywać typy obiektów za jednym zamachem, nie wiedząc (w czasie kompilacji), że wartość właściwego typu pudełkowego. Jednak czytając specyfikację języka Java lub wpisy na blogu, które zostały napisane w czasie Java 7 wyszedł, nie widzę żadnej zmiany tej rzeczy, więc zastanawiam się, co to jest zmiana i jak ta "funkcja" się nazywa?

Tylko ciekawostka: ze względu na zmianę, możliwe jest uruchomienie" złych " unboxingów:

Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];

To kompiluje dobrze, ale daje ClassCastException w czasie wykonywania.

Jakieś wzmianki na ten temat?
Author: Cœur, 2013-04-20

2 answers

Wygląda na to, że język w sekcja 5.5 Casting Conversion of Java 7 JLS został zaktualizowany w porównaniu do tej samej sekcji w Java 5/6 JLS, prawdopodobnie w celu wyjaśnienia dozwolonych konwersji.

Java 7 JLS says

Wyrażenie typu odniesienia może bez błędu przejść konwersję na typ prymitywny, przez rozpakowanie konwersji.

Java 5/6:

Wartość typu odniesienia może być oddana typowi prymitywnemu przez konwersja unboxingu (§5.1.8).

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 podstawowe. To jawnie wymienia rzuty od obiektu do prymitywów jako zawężającą konwersję odniesienia z unboxingiem.

Powód jest wyjaśniony w ten e-mail :

Podsumowując: jeśli spec. allows (Object) (int) musi być również allows(int) (Object).

 92
Author: Mark Rotteveel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-27 14:00:34

Masz rację; mówiąc prościej:

Object o = new Integer(1234);
int x = (int) o;

Działa to w Javie 7, ale powoduje błąd kompilacji w Javie 6 i poniżej. Co dziwne, ta funkcja nie jest wyraźnie udokumentowana; na przykład nie jest wymieniona tutaj . To dyskusyjne, czy jest to nowa funkcja lub poprawka błędu (lub nowy błąd?), zobacz kilka powiązanych informacji i dyskusji. Konsensus wydaje się wskazywać na dwuznaczność w oryginalnej specyfikacji, która doprowadziła do nieco niepoprawnej / niespójnej implementacji na Java 5/6, która została ustalona w 7, ponieważ była krytyczna dla implementacji JSR 292 (dynamicznie typowane języki).

Java autoboxing ma teraz więcej pułapek i niespodzianek. Na przykład

Object obj = new Integer(1234);
long x = (long)obj;

Skompiluje się, ale nie powiedzie się (z ClassCastException) w czasie wykonywania. To zamiast tego zadziała:

long x = (long)(int)obj;

 35
Author: leonbloy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-12 12:18:24