2013-04-20 2 views
106

Я заметил разницу в поведении автоматического разблокирования между Java SE 6 и Java SE 7. Мне интересно, почему это так, потому что я не могу найти документацию об изменениях в этом поведении между этими двумя версиями.Различия в auto-unboxing между Java 6 vs Java 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 (без какой-либо опции-источника). Он согласен и дает ту же ошибку, что и выше.

Так что же дает? Из нескольких экспериментов кажется, что 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, я не вижу никаких изменений в этой вещи, поэтому мне интересно, что такое изменение и что называется этой «функцией» ?

Просто любопытство: Из-за изменения, можно вызвать «неправильные» unboxings:

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: Хороший вопрос об упрощении, я немного упростил его (из моего исходного кода), но почему-то остановился слишком рано! – Morty

ответ

91

Похоже язык в section 5.5 Casting Conversion of Java 7 JLS был обновлен по сравнению с the same section in the Java 5/6 JLS, вероятно, уточнить допустимые преобразования.

Java 7 ПСБ говорит

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

Java 5/6:

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

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

Причина объясняется в this email:

Практический результат: Если в спецификации. позволяет (Object) (int) также разрешать (int) (Object).

+10

+1 для перехода к сути этого (JLS). –

35

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

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

Это работает в Java 7, но дает ошибку компиляции в Java 6 и ниже. Как ни странно, эта функция не задокументирована; например, не упоминается here. Это спорный вопрос, если это новая функция или ошибка исправления (или новая ошибка?), Увидеть некоторые related info and discussion. Консенсус, как представляется, указывает на ambiguity в оригинальной спецификации, что привело к слегка некорректной/несогласованной реализации на Java 5/6, которая была исправлена ​​в 7, поскольку это было важно для реализации JSR 292 (динамически типизированные языки).

Java autoboxing имеет теперь еще несколько ловушек и сюрпризов. Например

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

компилируется, но неудачно (с ClassCastException) во время выполнения. Это, вместо этого, будет работать:

long x = (long)(int)obj;

+2

Спасибо за ответ. Однако есть одна вещь, которую я не понимаю. Это разъяснение JLS и сопроводительных реализаций (см. Обсуждение почты), но почему это было бы сделано для размещения других типизированных языков в JVM? В конце концов, это изменение языка, а не виртуальной машины: поведение каста VM работает так, как оно всегда было, компилятор реализует эту функцию, используя существующий механизм для литья в Integer и вызов .intValue(). Итак, как это может измениться на языке Java, помогите запустить другие языки на виртуальной машине? Я согласен, что ваша ссылка предлагает это, просто интересно. – Morty

+2

@Morty: бьет меня – leonbloy

Смежные вопросы