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

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

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

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


person Brad Richards    schedule 17.09.2008    source источник
comment
IIRC JVM хранит байты и шорты как целые числа, поэтому обычно очень мало пользы от использования этих двух типов данных. Конечно, я понимаю, что вы делаете что-то гораздо более сложное, чем ваш пример, и, вероятно, у вас есть очень веская причина.   -  person Dave Webb    schedule 17.09.2008


Ответы (4)


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

person Brad Richards    schedule 17.09.2008
comment
Думаю, из-за производительности. В некоторых ЦП использование операндов меньшего размера, чем регистры ЦП, может оказаться более затратным. Вероятно, он даже использовал 32-битный int для хранения байтов и шорт, чтобы они были выровнены в памяти. - person jassuncao; 17.09.2008
comment
так как я обнаружил, что операции выполняются в регистрах ЦП, но да, они выровнены по 32 битам. и вы не можете выполнить оператор + на символах - person bestsss; 11.02.2011
comment
byte c = (byte)(a + b); после преобразования это выражение будет выглядеть так byte c = 57, где 57 имеет тип byte. Но тогда, поскольку числовое продвижение указывает, что все литералы byte, short и char преобразуются в int, этот байт 57 будет повышен до int 57. Таким образом, в этом смысле компилятор все равно должен выдавать ошибку, но это не так. Почему? - person user12208242; 20.08.2020

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

операнды типа byte и short автоматически повышаются до int перед передачей операторам

Итак, в вашем примере a и b оба преобразуются в int перед передачей оператору +. Результатом сложения двух int также является int. Попытка затем присвоить этому int значению byte приводит к ошибке, поскольку существует потенциальная потеря точности. Явно приводя результат, вы говорите компилятору: «Я знаю, что делаю».

person David Sykes    schedule 17.09.2008

Я думаю, дело в том, что JVM поддерживает только два типа значений стека: размером в слово и размером в двойное слово.

Затем они, вероятно, решили, что им понадобится только одна операция, которая работает с целыми числами размером в слово в стеке. Итак, на уровне байт-кода есть только iadd, imul и т. д. (и никаких операторов для байтов и шорт).

Таким образом, вы получаете значение int в результате этих операций, которые Java не может безопасно преобразовать обратно в меньшие байтовые и короткие типы данных. Таким образом, они заставляют вас выполнять приведение, чтобы сузить значение обратно до byte/short.

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

person jrudolph    schedule 17.09.2008

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

person Tom Hawtin - tackline    schedule 17.09.2008