Java - сдвиг битов с целыми числами и байтами

Рассмотрим следующий код (где byteIndex — это int):

int bitNumber = b-(8*byteIndex);
bitMask = 0x8>>(byte)bitNumber;

Это вызывает ошибку

error: possible loss of precision

при компиляции (требуемый байт, найдено целое число).

Код

int bitNumber = b-(8*byteIndex);
bitMask = 0x8>>2;

компилируется нормально.

В чем проблема и как исправить первый пример, чтобы разрешить сдвиг битов на значение int?

РЕДАКТИРОВАТЬ: после комментариев, вот более полный пример:

48) int byteIndex;
49) byte bitMask;
50) int bitNumber;
    // assign value to byteIndex
67) bitNumber = b-(8*byteIndex);
68) bitMask = 0x8>>bitNumber;

и указана ошибка:

...MyClass.java:68: error: possible loss of precision
    bitMask = 0x8>>bitNumber;
             ^
  required: byte
  found:    int
1 error

person Froskoy    schedule 28.09.2012    source источник
comment
Реальные ошибки Java имеют номера строк.   -  person President James K. Polk    schedule 28.09.2012
comment
Какой тип bitMask?? И типа b тоже??   -  person Rohit Jain    schedule 28.09.2012
comment
Если они типа int, то на моем компиляторе оба кода работают нормально..   -  person Rohit Jain    schedule 28.09.2012
comment
В вашем коде нет строки номер 68... честно: было бы очень полезно, если бы вы предоставили полный пример, в идеале включающий основной метод. Как @RohitJain, я не могу воспроизвести вашу проблему.   -  person Andreas Fester    schedule 28.09.2012
comment
@GregS: Если это так важно, я добавил номер строки, но не понимаю, как это делает вопрос более общим и помогает другим, у кого может возникнуть эта проблема? Или действительно, как это помогает людям ответить на этот конкретный вопрос?   -  person Froskoy    schedule 28.09.2012
comment
Я должен добавить, что битовая маска - это байт, и он должен оставаться таким.   -  person Froskoy    schedule 28.09.2012
comment
Да, вы должны добавить это к вопросу: p   -  person keyser    schedule 28.09.2012
comment
Если люди не могут это воспроизвести, значит, что-то еще мешает. Найдите его.   -  person keyser    schedule 28.09.2012


Ответы (3)


Преобразуйте свою строку shifting в это: -

byte bitMask = (byte)(0x8>>(byte)bitNumber);

Ваш RHS - это int, вам нужно преобразовать его в байт.

Приведенный выше код будет работать нормально. С или без casting от bitNumber до byte

Итак, вы также можете иметь: -

byte bitMask = (byte)(0x8>>bitNumber);

Но, вот вопрос - byte bitMask = 0x8>>3; работает нормально.. Почему так??

Вот пример, объясняющий причину его работы, а также поведение с final: -

byte bitMask;
int varInt1 = 3;
final int finalVarInt2 = 3;
final int finalVarInt3 = 4;

bitMask = 0x8>>varInt1;    // 1. Will not work. 
bitMask = 0x8<<3;          // 2. Will work

bitMask = 0x8<<4;          // 3. Will not work
bitMask = 0x8<<finalVarInt2;   // 1. Will work
bitMask = 0x8<<finalVarInt3;   // 2. Will not work

Вот несколько соображений, объясняющих описанное выше поведение: -

  • Значение на правой стороне будет typecasted неявно, только если компилятор уверен, что он сможет разместить это значение в переменной byte на левой стороне. В противном случае мы должны сделать Explicit type casting, чтобы сообщить компилятору, что мы знаем, что мы делаем. делают, просто сделайте это для нас..

Теперь давайте рассмотрим все случаи один за другим (из приведенного выше кода (1-3, 1-2): -

  1. varInt1 изначально содержит 3. Таким образом, значение RHS равно 64. Хотя это значение может быть размещено в переменной byte в LHS, но компилятор также знает об этом, можно изменить значение varInt1.. А что, если значение varInt1 на каком-то этапе изменится на 4.. Тогда это не сработает.. Вот почему это не разрешено..
  2. Теперь, в этом случае, поскольку мы явно использовали здесь Integer Literal, поэтому компилятор уверен, что он приспособится к byte. Таким образом, он допускает implicit< /strong> кастинг..
  3. Опять же, в этом случае известно, что RHS будет оцениваться как 128, что не может быть размещено в byte.. Ошибка снова..

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

  1. В этом случае компилятор увидит, что finalVarInt2 содержит значение 3. Таким образом, RHS оценивается как 64, что можно разместить в переменной byte в LHS. Теперь, поскольку переменная final, ее нельзя изменить, и Compiler знает об этом, поэтому он уверен, что t*его значение всегда будет 64*.. Итак, компилятор это позволяет.

  2. В последнем случае значение finalVarInt3 равно 4. Аналогичные рассуждения. >128, что не помещается в byte

person Rohit Jain    schedule 28.09.2012

В вашем первом примере битовое число представляет собой целое число (32 бита), и когда вы передаете его как байт (8 битов), вы теряете 24 бита старшего порядка. Поэтому вы теряете точность. Просто оставьте приведение (байт) выключенным.

person jalynn2    schedule 28.09.2012
comment
Я пропустил приведение, но все равно получаю ту же ошибку? bitMask — это байт, я должен был указать это раньше. - person Froskoy; 28.09.2012
comment
java -version печатает: версия java 1.7.0_06-icedtea - person Froskoy; 28.09.2012
comment
0x8 по умолчанию является целым числом, на самом деле. Достаточно просто сохранить внешний гипс. - person Fildor; 28.09.2012

На самом деле это не ответ, правильный ответ написал Рохит Джейн, но я впервые вижу такое поведение JVM, сравните эти коды:

версия, где bitNumber помечен как окончательная

final int bitNumber = 10;
final byte bitMask = 0x8 >> bitNumber;

версия, где bitNumber не является окончательной

int bitNumber = 10;
bitNumber = 10;
final byte bitMask = 0x8 >> bitNumber;

И есть ошибка - это второй пример, возможно, какая-то оптимизация. Было бы здорово, если бы кто-то знал причину ;-)

person Betlista    schedule 28.09.2012