Если вы объявляете переменные типа byte или short и пытаетесь выполнить с ними арифметические операции, вы получаете сообщение об ошибке «Несоответствие типов: невозможно преобразовать int в short» (или, соответственно, «Несоответствие типов: невозможно преобразовать int в byte»).
byte a = 23;
byte b = 34;
byte c = a + b;
В этом примере ошибка компиляции находится в третьей строке.
Хотя арифметические операторы определены для работы с любым числовым типом, согласно спецификации языка Java (5.6.2 Binary Numeric Promotion), операнды типа byte и short автоматически повышаются до int перед передачей операторам.
Чтобы выполнить арифметические операции с переменными типа byte или short, вы должны заключить выражение в круглые скобки (внутри которых операции будут выполняться как тип int), а затем привести результат обратно к желаемому типу.
byte a = 23; byte b = 34; byte c = (byte) (a + b);
Вот следующий вопрос настоящим гуру Java: почему? Типы byte и short - прекрасные числовые типы. Почему Java не позволяет выполнять прямые арифметические операции с этими типами? (Ответ - не «потеря точности», поскольку нет никакой очевидной причины для преобразования в int в первую очередь.)
Обновление: jrudolph предполагает, что это поведение основано на операциях, доступных в JVM, в частности, что реализованы только операторы полного и двойного слова. Следовательно, для операторов байтов и коротких замыканий они должны быть преобразованы в int.
Я думаю, это связано с производительностью. В некоторых процессорах может быть дороже использовать операнды меньшего размера, чем регистры процессора. Вероятно, он даже использовал 32-битное int для хранения байтов и коротких строк, чтобы они были выровнены в памяти.
так как я обнаружил, что - операции выполняются в регистрах процессора, но да, они выровнены на 32 бита. и вы не можете выполнить оператор + для символов
byte c = (byte)(a + b)
; после преобразования это выражение будет выглядеть как byte c = 57
, где 57 имеет тип byte. Но затем, поскольку числовое продвижение утверждает, что все литералы byte, short и char преобразуются в int, этот байт 57 будет повышен до int 57. Таким образом, в этом смысле компилятор все равно должен выдавать ошибку, но это не так. Почему?
Ответ на ваш дополнительный вопрос здесь:
operands of type byte and short are automatically promoted to int before being handed to the operators
Итак, в вашем примере a
и b
конвертируются в int
перед передачей оператору +. В результате сложения двух int
также получается int
. Попытка затем назначить этот int
значению byte
вызывает ошибку, поскольку есть потенциальная потеря точности. Явно приводя результат, вы говорите компилятору: «Я знаю, что делаю».
Я думаю, дело в том, что JVM поддерживает только два типа значений стека: размер слова и размер двойного слова.
Тогда они, вероятно, решили, что им понадобится только одна операция, которая работает с целыми числами в стеке. Таким образом, на уровне байт-кода есть только iadd, imul и т. д. (Без операторов для байтов и коротких замыканий).
Таким образом, в результате этих операций вы получаете значение int, которое Java не может безопасно преобразовать обратно в более мелкие байтовые и короткие типы данных. Таким образом, они заставляют вас использовать приведение, чтобы сузить значение до байтов / коротких.
Но, в конце концов, вы правы: например, такое поведение не согласуется с поведением int. Вы можете без проблем добавить две int и не получить ошибки, если результат выйдет за край.
Язык Java всегда продвигает аргументы арифметических операторов до int, long, float или double. Итак, возьмем выражение:
a + b
где a и b относятся к типу byte. Это сокращение для:
(int)a + (int)b
Это выражение имеет тип int. Очевидно, имеет смысл выдавать ошибку при присвоении значения int байтовой переменной.
Почему язык был определен таким образом? Предположим, что a было 60, а b было 70, тогда a + b равно -126 - целочисленное переполнение. Как часть более сложного выражения, которое должно было привести к int, это может стать сложной ошибкой. Ограничьте использование байтов и сокращений для хранения массива, констант для форматов файлов / сетевых протоколов и головоломок.
Есть интересная запись из JavaPolis 2007. Джеймс Гослинг приводит пример того, насколько сложна беззнаковая арифметика (и почему ее нет в Java). Джош Блох указывает, что его пример дает неверный пример и при обычной знаковой арифметике. Для понятной арифметики нам нужна произвольная точность.
IIRC JVM хранит байты и шорты как целые числа, поэтому обычно очень мало пользы от использования этих двух типов данных. Конечно, я понимаю, что вы делаете что-то гораздо более сложное, чем ваш пример, и, вероятно, имеете очень вескую причину.