2013-11-17 6 views
8

Я видел людей, задающих вопросы об ошибке «Тип несоответствия: невозможно преобразовать int в байт». Но они в основном вызваны арифметическими операциями.«Несоответствие типа: невозможно преобразовать 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

ответ

10

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

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

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

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

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

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

+0

@ jprofitt: Oh. Прицепи, ты прямо здесь. Это ... может изменить ответ ... Надо кое-что прочитать. –

+0

На самом деле, я еще больше запутался. Согласно спецификации языка, нет байтовых литералов. Поэтому ни один из этих случаев не должен работать ... –

+0

Спасибо за помощь! Я тоже считал цифры 2 минуты назад ... Я должен добавить длину комментариев, чтобы улучшить читаемость. –

3

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

+0

В представлении комплиментов двух, 0b10000000 is -128, который все еще находится в диапазоне от int в java. –

+0

Правильно, но вы пытались сделать байт, следовательно, ошибка. Байт типа не может удерживать значение 0b10000000 – richard

+0

+1 для того, чтобы проложить путь сюда, я согласитесь, это должен быть ответ. Добавил немного подробностей к этому, см. мой ответ. –

1

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

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

Смежные вопросы