Продвижение типа в Java
У меня проблема с приведенными ниже инструкциями Java:
byte b = 10;
byte r = (byte) (b * b); // Giving correct result
byte r = (byte) b * b; // Giving error " POSSIBLE LOSS OF PRECISION"
Почему обязательно ставить скобки в b * b
?
Ответы
Ответ 1
(byte) b * b
преобразует значение первого b
в byte
(которое является избыточным, поскольку оно уже было byte
) и умножает его на значение второго b
. Умножение двух byte
переводит их в int
первым, так как для byte
s нет оператора *
. Следовательно, результатом является int
, и его нельзя присвоить byte
переменной.
С другой стороны, (byte)(b * b)
приводит результат умножения int
к byte
, который может быть присвоен byte
переменной.
Это описано в JLS в 5.6.2. Двоичное числовое продвижение:
Когда оператор применяет двоичное числовое продвижение к паре операндов, каждый из которых должен обозначать значение, которое может быть преобразовано в числовой тип, применяются следующие правила по порядку:
-
Если какой-либо операнд имеет ссылочный тип, он подвергается распаковке преобразования (§5.1.8).
-
Расширяющее примитивное преобразование (§5.1.2) применяется для преобразования одного или обоих операндов, как указано в следующих правилах:
-
Если один из операндов имеет тип double, другой преобразуется в double.
-
В противном случае, если один из операндов имеет тип float, другой преобразуется в float.
-
В противном случае, если один из операндов имеет тип long, другой преобразуется в long.
-
В противном случае оба операнда преобразуются в тип int.
Ответ 2
Проблема литья
byte r = (byte) (b * b);
Приводит (byte)
тип к результату (b * b)
byte r = (byte) b * b;
Он преобразует (byte)
тип только в первый b
, поэтому он станет ((byte) b) * b
Ответ 3
По правилу приоритета вы приводите только первый b к байту вместо всего результата.
И Java следуют некоторым правилам, как вы можете видеть здесь
Все целочисленные значения (byte, short и int) в арифметических операциях (+
, −
, *
, /
, %
) преобразуются в тип int
перед выполнением арифметической операции. Однако, если одно из значений в арифметической операции (+
, −
, *
, /
, %
) является long
, то все значения преобразуются в long
тип перед выполнением арифметической операции.
Итак, просто бросая первый b
вы делаете это:
byte = byte * integer
Следовательно:
byte = integer
Таким образом, возникла ошибка.
Ответ 4
Переменные byte
типа должны быть [-128, 127], поэтому компилятор не должен принимать никаких операций, b*b;b+b;bb;b/b
без приведения к результату операции, например: (byte)(b*b)
.
В приведенном ниже коде при изменении типа результата на int
он компилируется.
byte b=10;
byte c=(byte)b*b; //incompatible but correct when c is int
byte d=((byte)b)*b; //incompatible but correct when d is int
byte r=(byte)(b*b);
byte t= b*b; //incompatible but correct when t is int
byte e=(byte)b/b; //incompatible but correct when e is int
byte f=((byte)b)/b; //incompatible but correct when f is int
byte o=(byte)(b/b);
byte w=b/b; //incompatible but correct when w is int
byte g=(byte)b+b; //incompatible but correct when g is int
byte p=((byte)b)+b; //incompatible but correct when p is int
byte q=(byte)(b+b);
byte x=b+b; //incompatible but correct when x is int
byte h=(byte)b-b; //incompatible but correct when h is int
byte v=((byte)b)-b; //incompatible but correct when v is int
byte s=(byte)(b-b);
byte y=b-b; //incompatible but correct when y is int
byte k=(byte)b;
byte u=b;
НОТА
Как отметил @andy Truner в комментариях, когда b
является final
, все предыдущие инструкции компилируются !!, за исключением следующих настроек:
final byte fn=-120;
byte z=fn-b; //this does not compile even when both final, because the result would be -130, out of the byte type interval!!