Java позволяет назначать байт для java.lang.Short, но не для java.lang.Integer

final byte b = 12;  
Short s = b;  
Integer i = b;

Программа компилируется нормально для Short, но компиляция для Integer завершается с ошибкой с сообщением "несовместимые типы".

Мне трудно понять это поведение. Я не мог найти ничего для этого конкретного сценария.


person Pawel Mercik    schedule 13.08.2014    source источник
comment
используйте int вместо Integer   -  person Sanjay Dutt    schedule 13.08.2014
comment
Это не 100% дубликат, потому что в нем не указано, почему Short разрешено, а Integer нет, поэтому я отказался от закрытия. Тем не менее очень связано: stackoverflow.com/questions/7014171/< /а>   -  person Jeroen Vannevel    schedule 13.08.2014
comment
На мой взгляд, на очень близкий вопрос нет адекватного ответа - просто есть группа людей, делающих дикие предположения. Я думаю, что было бы ошибкой закрывать это.   -  person Dawood ibn Kareem    schedule 13.08.2014
comment
Не только это, но и правильный ответ на очень связанный вопрос неверен. Очевидно, что byte автоматически упаковывается в Short, хотя Short больше байта. Так почему бы не работать с преобразованием байта в целое число? Это потому, что это больше, чем на 2 уровня невнимательности выше? Кажется произвольным.   -  person Hypino    schedule 13.08.2014
comment
Сюжет усложняется: удаление ключевого слова final приводит к тому, что автоупаковка Short также генерирует ошибку компилятора. Это может быть ключом к разгадке причины такого странного поведения.   -  person Kevin Workman    schedule 13.08.2014
comment
И еще странный нюанс: Character c = b тоже прекрасно компилируется. Но char без знака! Итак, что происходит, когда вы меняете b на -12? Затем он не компилируется!   -  person Mark Peters    schedule 13.08.2014


Ответы (1)


Я попытался продублировать это с более широкой группой контекстов назначения:

final byte b = 12;
Byte b2 = b;
Character c = b;  // Only an error if b isn't final
char c2 = b;      // Only an error if b isn't final
Short s = b;      // Only an error if b isn't final
short s2 = b;
Integer i = b;  // Error, as indicated in the question
int i2 = b;
Long l = b;     // Also an error
long l2 = b;
Float f = b;    // Also an error
float f2 = b;
Double d = b;   // Also an error
double d2 = b;

Назначение не только Integer, но и Float, Long или Double также является ошибкой.

Интересно, что если исходное объявление b НЕ было final, то присваивание Character, char или Short также не удается.

Раздел 5.2 JLS проливает немного света на тему контекстов присваивания и их разрешенных преобразований.

Контексты назначения позволяют использовать одно из следующего:

  • преобразование идентичности (§5.1.1)

  • расширяющее примитивное преобразование (§5.1.2)

  • расширяющее преобразование ссылки (§5.1.5)

  • преобразование бокса (§5.1.7), за которым необязательно следует преобразование расширяющей ссылки

  • распаковывающее преобразование (§5.1.8), за которым необязательно следует расширяющее примитивное преобразование.

Это охватывает все преобразования в более широкие примитивные переменные, которые разрешены всегда, независимо от того, является ли b final или нет. (Это верно, если b не является отрицательным, и в этом случае присваивание беззнаковому char (или Character) не удастся.) Продолжаем:

Кроме того, если выражение является константным выражением (§15.28) типа byte, short, char или int:

  • Сужающее примитивное преобразование может использоваться, если переменная имеет тип byte, short или char, а значение константного выражения может быть представлено в типе переменной.

  • Сужающее примитивное преобразование, за которым следует упаковывающее преобразование, может использоваться, если тип переменной:

    • Byte и значение константного выражения можно представить в виде byte.

    • Short, а значение константного выражения можно представить в виде short.

    • Символ и значение константного выражения можно представить в виде char.

Поскольку b равно final, выражение b является постоянным выражением, что позволяет сузить его от int постоянного выражения 12 до byte, char или short, а затем упаковать в Byte, Character или Short, но странно, не до Integer или чего-то выше. Единственное возможное объяснение, которое я могу придумать, состоит в том, что выражения-константы, которые подвергаются примитивному сужающему преобразованию, специально не могут быть преобразованы в Integer, Long, Float или Double.

Если b не равно final, то сужение с последующим боксом не разрешено, и непостоянное выражение также не может быть повышено с byte до char.

person rgettman    schedule 13.08.2014
comment
Character c = b; // Only an error if b isn't final (или b отрицательное значение) Отличный ответ! - person Mark Peters; 13.08.2014
comment
@MarkPeters Верно. Как указано в приведенной выше цитате JLS, значение константного выражения может быть представлено в типе переменной. Отрицательное значение final b также приведет к сбою char c = b; с ошибкой. - person rgettman; 13.08.2014
comment
но, как ни странно, не для Integer или чего-либо выше Я думаю, что этого следовало ожидать, поскольку в этот момент вы работаете с Short и Integer, и расширение для этих типов обертки невозможно. См. $JLS 5.1.5.: существует расширяющее преобразование ссылок из любого ссылочного типа S в любой ссылочный тип T при условии, что S является подтипом T. и, очевидно, нет прямой связи между Short и Integer. - person Jeroen Vannevel; 13.08.2014
comment
@JeroenVannevel Да, но мне показалось странным, что расширенное примитивное преобразование, за которым следует преобразование бокса, специально не разрешено. - person rgettman; 13.08.2014