Відмінності в автоматичному розпакуванні між Java 6 та Java 7


107

Я зазначив різницю в поведінці автоматичного розпакування між Java SE 6 та Java SE 7. Мені цікаво, чому це так, тому що я не можу знайти жодної документації про зміни в цій поведінці між цими двома версіями.

Ось простий приклад:

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

Це добре поєднується з javac від Java SE 7. Однак, якщо я даю компілятору аргумент "-source 1.6", я отримую помилку в останньому рядку:

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

Я спробував завантажити Java SE 6 для компіляції з нативним компілятором версії 6 (без будь-якої опції -source). Він погоджується і дає ту саму помилку, що і вище.

То що дає? З деяких додаткових експериментів видається, що розблокування в Java 6 може розблокувати лише ті значення, які явно (під час компіляції) мають тип коробки. Наприклад, це працює в обох версіях:

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

Отже, здається, що між Java 6 та 7 функція розпакування була розширена, щоб вона могла видавати та розпаковувати типи об’єктів одним махом, не знаючи (під час компіляції), що значення має відповідний тип коробки. Однак, читаючи специфікацію мови Java або публікації блогу, написані в той час, коли з'явилася Java 7, я не бачу жодної зміни в цьому, тому мені цікаво, що це за зміна і як називається ця "особливість" ?

Просто цікавість: Завдяки зміні можливо запустити "неправильні" розпакування:

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

Це добре поєднує, але дає ClassCastException під час виконання.

Будь-яка посилання на це?


17
Цікаво. Новий інгредієнт для безладу автобоксу. Я думаю, що ваш приклад міг бути більш простим і зрозумілим з одним об’єктом замість масиву. Integer obj = new Integer(2); int x = (int)obj;: працює на Java 7, дає помилку на Java 6.
leonbloy

1
Який JDK ви використовуєте? Це також може
стосуватися

1
@leonbloy: Добрий момент щодо спрощення, я дещо спростив його (з мого початкового коду), але якось зупинився занадто рано!
Морті

@Thomas: Я використовував останню версію JDK (для кожної версії) від Oracle.
Морті

2
Ще одна причина ніколи не використовувати автобоксинг.
gyorgyabraham

Відповіді:


92

Схоже, мова в розділі 5.5 Передача конвертації Java 7 JLS була оновлена ​​порівняно з тим же розділом JLS Java 5/6 , ймовірно, для уточнення дозволених перетворень.

Каже Java 7 JLS

Вираз еталонного типу може піддаватися перетворенню кастингу в примітивний тип без помилок шляхом розпаковування конверсії.

Java 5/6:

Значення еталонного типу може бути передано примітивному типу шляхом розблокування перетворення (§5.1.8).

Java 7 JLS також містить таблицю (таблиця 5.1) дозволених перетворень (ця таблиця не включена в Java 5/6 JLS) від типів посилань до примітивів. Це явно перераховує касти від Object до примітивів як звуження перетворення еталону при розпакуванні.

Причина пояснюється в цьому електронному листі :

Підсумок: Якщо специфікація. дозволяє (Об'єкт) (int), він також повинен дозволяти (int) (Object).


35

Ти правий; простіше кажучи:

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

Це працює в Java 7, але дає помилку компіляції в Java 6 і нижче. Як не дивно, ця особливість не є чітко зафіксованою; наприклад, не згадується тут . Це спірне питання, якщо це нова функція чи виправлення помилок (чи нова помилка?), Див. Деяку пов’язану інформацію та обговорення . Здається, що консенсус вказує на неоднозначність в оригінальній специфікації, що призвело до дещо некоректної / непослідовної реалізації Java 5/6, яка була зафіксована у 7, оскільки вона була критичною для впровадження JSR 292 (Динамічно типізовані мови).

Java-автобоксинг тепер має ще кілька пасток і сюрпризів. Наприклад

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

буде компілюватися, але не (з ClassCastException) під час виконання. Натомість це спрацює:

long x = (long)(int)obj;


2
Дякую за відповідь. Однак є одне, чого я не розумію. Це уточнення JLS та супровідних реалізацій (див. Дискусійну пошту), але навіщо це робити для розміщення інших набраних мов у JVM? Зрештою, це зміна мови, а не VM: поведінка кастингу VM працює як завжди, компілятор реалізує цю функцію, використовуючи існуючий механізм кастингу до Integer та виклику .intValue (). Тож як це могло змінити мову мови Java, допомогти запустити інші мови у віртуальній машині? Я згоден, що ваше посилання говорить про це, просто цікаво.
Морті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.