Как известно, в Java нет беззнаковых типов. Если в Си вы могли написать
unsigned int
(
char
,
long
), то в Java так не получится. Однако нередко возникает необходимость в выполнении арифметических операций именно с числами без знака. На первый взгляд кажется, что беззнаковые типы в принципе-то и не особо нужны (подумаешь,
MaxInt
для чисел со знаком меньше в два раза, если нужны числа больше, я просто возьму
long
и далее
BigInteger
). Но основное различие на самом деле не в том, сколько различных неотрицательных чисел можно положить в signed или unsigned int, а в том, как над ними производятся арифметические операции и сравнения. Если вы работаете с бинарными протоколами или с двоичной арифметикой, где важен каждый используемый бит, нужно уметь выполнять все основные операции в беззнаковом режиме. Рассмотрим эти операции по порядку:
Преобразование byte в short (int, long)
Обычный каст
(int) myByte
выполнит расширение до 32 бит со знаком — это означает, что если старший бит байта был установлен в 1, то результатом будет то же самое отрицательное число, но записанное в 32-битном формате:
0xff -> 0xffffffff (-1)
Часто это не то, чего бы мы хотели. Для того, чтобы выполнить расширение до 32 бит без знака и получить
0x000000ff
, в Java можно записать:
int myInt = myByte & 0xff;
short myShort = myByte & 0xff;
Сравнение без учёта знака
Для беззнакового сравнения есть лаконичная формула:
int compareUnsigned(int a, int b) {
return Integer.compare( a ^ 0x80000000, b ^ 0x80000000 );
}
Для byte, short и long, соответственно, константы будут
0x80
,
0x8000
и
0x8000000000000000L
.