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

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

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

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

Ответы [ 4 ]

8 голосов
/ 17 сентября 2008

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

5 голосов
/ 17 сентября 2008

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

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

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

2 голосов
/ 17 сентября 2008

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

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

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

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

1 голос
/ 17 сентября 2008

Язык Java всегда поддерживает аргументы арифметических операторов для int, long, float или double. Итак, возьмите выражение:

a + b

где a и b имеют тип байта. Это сокращение для:

(int)a + (int)b

Это выражение имеет тип int. Очевидно, имеет смысл выдавать ошибку при назначении значения int байтовой переменной.

Почему язык должен быть определен таким образом? Предположим, что a равно 60, а b равно 70, тогда a + b равно -126 - целочисленное переполнение. Как часть более сложного выражения, которое должно было привести к int, это может стать трудной ошибкой. Ограничьте использование байтов и кратких для хранения массивов, констант для форматов файлов / сетевых протоколов и головоломок.

Есть интересная запись из JavaPolis 2007. Джеймс Гослинг приводит пример того, как сложна арифметика без знака (и почему она не в Java). Джош Блох указывает, что его пример дает неправильный пример и в обычной знаковой арифметике. Для понятной арифметики нам нужна произвольная точность.

...