"Несоответствие типов: невозможно преобразовать int к Byte"

Я видел, как люди задавали вопросы об ошибке "несоответствие типа: не удается преобразовать int в байт". Но они в основном вызваны арифметическими операциями.

вот мой случай:
(Это происходит, когда я хочу играть с битами в Eclipse Kepler)

//java 7 binary literals

byte a =  0b01111111; //8-bit it compiles 

byte b =  0b10000000;  //8-bit error: Type mismatch: cannot convert int to byte.                        

byte c =  (byte) 0b10000000; //8-bit it works fine if casted.

дело в том, что если это 8 бит и высокая цифра 1, то компилятор выдает ошибку. Я хочу знать, почему. Префикс 0b означает, что это двоичный литерал, поэтому компилятор принимает самую высокую цифру как подписанная цифра int или что-то в этом роде?

Спасибо за ответ.

[Edit3:]

byte a = -128; //a = 0xFF = 11111111 (8 bits), compiler says ok.
byte b = 0b11111111; //compiler error

[Edit2: побитовая & операция как-то запускает ошибку, а также]

byte a = 0b00000000;  //8 bits
a = (a&0xFF);  //gives same error: Type mismatch: cannot convert int to byte
a = (byte)(a&0xFF); //it is fine to cast

[Edit1: скриншот обновлено] enter image description here

enter image description here

3 ответов


вы получили точку, подозревая, что речь идет о целых числах со знаком. В Java все целые числа типов (byte, short, int, long) всегда подписаны. Java использовала дополнение two для хранения подписанных (прочитанных "всех") значений. Это в основном означает, что если первый бит любого типа (не первый бит, указанный в литерале, но первый бит хранится) равен 1, число отрицательно. Если 0, то положительный.

второе, что важно: в Java нет байтовых литералов. Есть int литералы, и long литералы. Каждый записанный nubmer (будь то двоичный (префикс 0b), восьмеричный (префикс 0), десятичный (без префикса) или шестнадцатеричный (префикс 0x)) является целочисленным литералом, если вы не добавляете L (в Нижнем или верхнем регистре), это long. Нет никакого способа записать любой short или byte напрямую.

теперь это означает, что все те примеры, которые вы записали, создают int первый. Вы не создаете byteтам.

Итак, последние часть, что произойдет, если вы попытаетесь сохранить это int внутри byte - без литья или с литьем. Если вы бросаете явно, вы в основном говорите Java просто игнорировать любые биты, которые не подходят. Они будут сокращены-даже если это изменит значение числа (примеры см. ниже). Если ты не бросишь, кусочки все равно будут отрезаны. Но Java этого не сделает, если он изменит значение - чтобы убедиться, что вы действительно имеете в виду то, что делаете.

чтобы связать все это с exmamples из вопрос:
int 0b01111111 составляет 127
byte 0b01111111 составляет 127
- >преобразование возможно без переполнения, поэтому Java сделает это даже без явного приведения

int 0b10000000 составляет 128
byte 0b10000000 is -128
-> Переполнение occrus при конвертации, так что Java будет выдавать ошибку, если нет явного приведения.


Я думаю, что байты в java подписаны, что сделало бы 0b10000000 вне диапазона. 127 был бы самым большим байтом, возможным, причиной которого является комплиментарное представление отрицательных чисел.


байтовые переменные могут содержать значение 0b1000000, но поскольку они подписаны, это представляет собой целое значение -128. Причина, по которой он не может преобразовать литерал, заключается в том, что когда вы пишете его как литерал без приведения, компилятор видит его как (int) 0b10000000, который является целочисленным значением POSITIVE 128.

любое целочисленное значение выше 127 не подходит для байта, поскольку байты подписаны и могут содержать только целочисленные значения от -128 до 127. Вот где происходит переполнение (для хранения 128, вам понадобится девятый бит для знака). Каждый раз, когда подписали стоимость 1 своим наиболее значимым, представляет собой отрицательное число, поэтому для того, чтобы поставить рядом как 0b10000000 в байт, нужно представлять отрицательное значение в буквальном. Например, значение -128 будет эквивалентно инт 0b11111111111111111111111110000000, так что вы должны использовать его в качестве литерала, или же, гораздо проще, просто явно привести его в байт, как: (байт) 0b10000000