Различия в автоматическом распаковке между Java 6 и Java 7

Я заметил разницу в поведении автоматического распаковки между 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. Однако, если я дам компилятору аргумент "-Инструмент 1.6", я получаю сообщение об ошибке в последней строке:

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

Я попробовал загрузить Java SE 6 для компиляции с компилятором собственной версии 6 (без опции -source). Он согласен и дает ту же ошибку, что и выше.

Итак, что дает? Из нескольких экспериментов кажется, что unboxing в Java 6 может только unbox-значения, которые ясно (во время компиляции) имеют тип в штучной упаковке. Например, это работает в обеих версиях:

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

Таким образом, кажется, что между Java 6 и 7 функция распаковки была улучшена, так что она могла создавать и удалять типы объектов одним махом, не зная (во время компиляции), что значение имеет соответствующий тип в штучной упаковке. Тем не менее, чтение через Java Language Specification или сообщения в блоге, которые были написаны в то время, когда вышла Java 7, я не вижу никаких изменений в этой вещи, поэтому мне интересно, что такое изменение и что называется этой "функцией"

Просто любопытство: из-за изменения можно вызвать "неправильные" распаковки:

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

Это компилируется отлично, но во время выполнения предоставляет ClassCastException.

Любая ссылка на это?

Ответ 1

Похоже на язык в в разделе 5.5. Кастингное преобразование Java 7 JLS обновлено по сравнению с тем же разделом в Java 5/6 JLS, возможно, для уточнения разрешенных преобразований.

Java 7 JLS говорит

Выражение ссылочного типа может подвергаться преобразованию каста в примитивный тип без ошибок, путем преобразования с помощью unboxing.

Java 5/6:

Значение ссылочного типа может быть передано примитивному типу путем распаковки преобразования (п. 5.1.8).

Java 7 JLS также содержит таблицу (таблица 5.1) разрешенных преобразований (эта таблица не включена в Java 5/6 JLS) из ссылочных типов в примитивы. Это явно перечисляет отрывки из объекта в примитивы как сужение ссылочного преобразования с распаковкой.

Объяснение объясняется в этом электронном письме:

Нижняя строка: если спецификация. позволяет (Object) (int) также разрешать (int) (Object).

Ответ 2

Вы правы; проще говоря:

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;