Java-почему char получает неявное приведение к примитиву byte (и short), когда это не должно?

некоторые функции компилятора озадачивают меня (Oracle JDK 1.7 с использованием Eclipse).

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

другими словами, ниже код работает (но не будет работать без явных приведений типов):

char c = '&';  
byte b = (byte)c;
short s = (short)c;

печать b или s правильно отображает число 38, которое является числовым эквивалентом ( & ) в Юникод.

что подводит меня к моему фактическому вопросу. Почему работает и следующее?

byte bc = '&';
short sc = '&';
System.out.println(bc); // Correctly displays number 38 on the console
System.out.println(sc); // Correctly displays number 38 on the console

теперь я бы, конечно, понял следующее (что тоже работает):

byte bt = (byte)'&';
System.out.println(bt); // Correctly displays number 38 on the console

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

может кто-нибудь объяснить, почему это допускают?

может быть, причина в интерпретации '<char>' сам, так что он на самом деле никогда не попадает в примитивное состояние char, но обрабатывается как числовое (восьмеричное или шестнадцатеричное и т. д.) значение?

5 ответов


в основном спецификация преобразования назначения указывает, что

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

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

код '&' Это точно "постоянное выражение типа byte, short, char или int".


Это называется сужение констант во время компиляции. Это описано в разделе 5.2 спецификации языка Java:

сужение времени компиляции констант означает, что код, такой как:

byte theAnswer = 42;

разрешено. Без сужения, тот факт, что целочисленный литерал 42 имеет тип int будет означает, что потребуется приведение к byte.

то же самое касается символьных литералов: если его значение соответствует byte, преобразование не требуется; если значение не подходит, вы должны поместить в приведение, или вы получите ошибку компиляции.

например, это не будет компилироваться:

byte bc = '\uff12'; // Does not compile without a cast

но это прекрасно компилируется:

byte bc = (byte)'\uff12';

Я не знаю, достаточно ли этого объяснения или нет, но это поведение определено в JLS. От JLS, раздел 5.2:

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

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

почему работает следующее?

, потому что '&' - постоянное выражение, значение которого соответствует byte.

JLS 14.4.2

Если Декларатор имеет выражение инициализации, выражение вычисляется и его значение присваивается переменной.

JLS 5.2

преобразование присваивания происходит, когда значение выражения присваивается (§15.26) переменной: тип выражения должен быть преобразован в тип переменной.

....

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

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

выражение"&", которое находится в вашем инициализаторе для переменной bc, является постоянным выражением. Выражение c, которое находится в инициализаторе для переменных b и s, не является постоянным выражением. Java выполняет неявные сужающие преобразования примитивов, когда этого требует контекст когда значение является результатом постоянного выражения только.