Java:почему я получаю сообщение об ошибке “Несоответствие типов:не удается преобразовать значение int в байт”
-
09-06-2019 - |
Вопрос
Если вы объявляете переменные типа byte или short и пытаетесь выполнить с ними арифметические операции, вы получаете сообщение об ошибке "Несоответствие типа:не удается преобразовать int в short" (или, соответственно, "Несоответствие типов:не удается преобразовать int в байт").
byte a = 23;
byte b = 34;
byte c = a + b;
В этом примере ошибка компиляции находится в третьей строке.
Решение
Хотя арифметические операторы определены для работы с любым числовым типом, согласно спецификации языка 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 .)
Обновить:юдольф предполагает, что такое поведение основано на операциях, доступных в JVM, в частности, на том, что реализованы только операторы с полным и двойным словом.Следовательно, для работы с байтами и короткими записями они должны быть преобразованы в int.
Другие советы
Ответ на ваш последующий вопрос находится здесь:
операнды типа byte и short автоматически преобразуются в int перед передачей операторам
Итак, в вашем примере, a
и b
оба преобразуются в int
перед передачей оператору +.Результат сложения двух int
s вместе - это тоже int
.Пытаясь затем присвоить это int
к a byte
значение вызывает ошибку, поскольку существует потенциальная потеря точности.Явно приводя результат, вы сообщаете компилятору: "Я знаю, что я делаю".
Я думаю, дело в том, что JVM поддерживает только два типа значений стека:размер слова и двойной размер слова.
Затем они, вероятно, решили, что им понадобится только одна операция, которая работает с целыми числами размером со слово в стеке.Таким образом, на уровне байт-кода есть только iadd, imul и так далее (и никаких операторов для байтов и коротких замыканий).
Таким образом, в результате этих операций вы получаете значение int, которое Java не может безопасно преобразовать обратно в меньшие байтовые и короткие типы данных.Таким образом, они заставляют вас выполнять приведение, чтобы сузить значение обратно до байта / короткого.
Но в конце концов вы правы:Например, такое поведение не согласуется с поведением целых чисел.Вы можете без проблем добавить два целых числа и не получить ошибки, если результат переполнится.
Язык Java всегда переводит аргументы арифметических операторов в значения int, long, float или double .Итак , возьмем выражение:
a + b
где a и b имеют тип byte.Это сокращение для:
(int)a + (int)b
Это выражение имеет тип int.Очевидно, что имеет смысл выдавать ошибку при присвоении значения int переменной byte.
Почему язык должен быть определен таким образом?Предположим, что a равно 60, а b равно 70, тогда a+b равно -126 - целочисленное переполнение.Как часть более сложного выражения, которое, как ожидалось, приведет к int , это может стать сложной ошибкой.Ограничьте использование байтового и короткого хранилища в массив, констант для форматов файлов / сетевых протоколов и головоломок.
Есть интересная запись из JavaPolis 2007.Джеймс Гослинг приводит пример того, насколько сложна арифметика без знака (и почему ее нет в Java).Джош Блох указывает, что его пример также дает неверный пример при обычной знаковой арифметике.Для понятной арифметики нам нужна произвольная точность.