Различия в автоматической распаковке между 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. Однако, если я дам компилятору аргумент "- source 1.6", я получу ошибку в последней строке:
inconvertible types
found : java.lang.Object
required: int
Я попытался загрузить Java SE 6 для компиляции с родной версией 6 компилятор (без опции any-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 во время выполнения.
Какие-нибудь ссылки на это?
2 ответа:
Похоже, что язык в разделе 5.5 приведение преобразования Java 7 JLS был обновлен по сравнению с тем же разделом в Java 5/6 JLS, вероятно, для уточнения разрешенных преобразований.
Java 7 JLS говорит
Выражение ссылочного типа может подвергаться преобразованию приведения к примитивному типу без ошибок путем распаковки преобразования.
Java 5/6:
Java 7 JLS также содержит таблицу (Таблица 5.1) разрешенных преобразований (эта таблица не включена в Java 5/6 JLS) от ссылочных типов к примитивам. Это явно перечисляет приведения от объекта к примитивам как сужающее ссылочное преобразование с распаковкой.Значение ссылочного типа может быть приведено к примитивному типу с помощью распаковыванию преобразования (§5.1.8).
Причина объяснена в этом письме:
Итог: Если спецификация. allows (Object) (int) это также должно быть allowing(int) (объект).
Вы правы; проще говоря:
Object o = new Integer(1234); int x = (int) o;
Это работает в Java 7, но дает ошибку компиляции в Java 6 и ниже. Как ни странно, эта особенность не задокументирована; например, она не упоминается здесь. Это спорно, если это новая функция или исправление ошибки (или новая ошибка?), смотрите некоторыесвязанные сведения и обсуждения . Консенсус, по-видимому, указывает на двусмысленность в исходной спецификации, что привело к слегка неправильной / непоследовательной реализации на Java 5/6, которая была исправлена в 7, потому что это было критично для реализации JSR 292 (динамически типизированные языки).
Java autoboxing теперь имеет еще несколько ловушек и сюрпризов. Например
Object obj = new Integer(1234); long x = (long)obj;
Будет компилироваться, но потерпит неудачу (с
ClassCastException
) во время выполнения. Это, напротив, будет работать:
long x = (long)(int)obj;