Java: почему я получаю сообщение об ошибке «Несоответствие типов: невозможно преобразовать int в байт»

Если вы объявляете переменные типа byte или short и пытаетесь выполнить с ними арифметические операции, вы получаете сообщение об ошибке «Несоответствие типов: невозможно преобразовать int в short» (или, соответственно, «Несоответствие типов: невозможно преобразовать int в byte»).

byte a = 23;
byte b = 34;
byte c = a + b;

В этом примере ошибка компиляции находится в третьей строке.

IIRC JVM хранит байты и шорты как целые числа, поэтому обычно очень мало пользы от использования этих двух типов данных. Конечно, я понимаю, что вы делаете что-то гораздо более сложное, чем ваш пример, и, вероятно, имеете очень вескую причину.

Dave Webb 17.09.2008 13:29
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
11
1
23 465
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Хотя арифметические операторы определены для работы с любым числовым типом, согласно спецификации языка 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 для хранения байтов и коротких строк, чтобы они были выровнены в памяти.

jassuncao 17.09.2008 14:39

так как я обнаружил, что - операции выполняются в регистрах процессора, но да, они выровнены на 32 бита. и вы не можете выполнить оператор + для символов

bestsss 11.02.2011 16:15

byte c = (byte)(a + b); после преобразования это выражение будет выглядеть как byte c = 57, где 57 имеет тип byte. Но затем, поскольку числовое продвижение утверждает, что все литералы byte, short и char преобразуются в int, этот байт 57 будет повышен до int 57. Таким образом, в этом смысле компилятор все равно должен выдавать ошибку, но это не так. Почему?

user12208242 20.08.2020 12:02

Ответ на ваш дополнительный вопрос здесь:

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). Джош Блох указывает, что его пример дает неверный пример и при обычной знаковой арифметике. Для понятной арифметики нам нужна произвольная точность.

Другие вопросы по теме