Битовые операторы работают точно так, как вы ожидаете.Они являются строгими бит-операторами и вообще не учитывают семантику битов.
Иногда проще всего выполнить код, используя точки останова.Для вашего конкретного примера я преобразовал шаги операции в атомарные операторы и напечатал результаты с помощью Long.toString
.
int x = -57;
// step 1:
long xCast = (long) x;
System.out.println(Long.toString(xCast, 2)); // -1110011 - this is not the bitwise representation however.
long mask = 0xffffffffL;
System.out.println(Long.toString(mask, 2)); // 11111111111111111111111111111111
// step 2:
long result = ((long) x) & mask;
System.out.println(Long.toString(result, 2)); // 11111111111111111111111111000111
Шаг 1 - основная причина, по которой операция выглядит так, как она выглядит.В Java все (строго числовые) значения подписаны (символы без знака).Это означает, что, как вы правильно сказали, все старшие биты являются знаковыми битами.Однако интересная часть - это то, что делают остальные биты, если число отрицательно.Следующий поток уже охватывал основы «дополнения к двум»: Что такое «дополнение к двум»? Так же, как эта страница википедии: https://en.wikipedia.org/wiki/Two%27s_complement
Чтобы сделать его коротким, в Java, для целых чисел:
int zero = 0; // == 0b00000000_00000000_00000000_00000000
int maxPositive = Integer.MAX_VALUE; // == 0b01111111_11111111_11111111_11111111
int minus1 = -1; // == 0b11111111_11111111_11111111_11111111
int minNegative = Integer.MIN_VALUE; // == 0b10000000_00000000_00000000_00000000
Таким образом, причина, по которой все работает, в том, что если целое число отрицательно, когда оно приведено, все старшие 32 бита преобразуются в 1 с, потому что в противном случае представленное значение числаизменилось бы.фактически:
int x = 0b11111111_11111111_11111111_11000111;
приводится к:
long xCast = 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11000111;
Поскольку вы, как разработчик, ожидаете, что метод вернет только первоначально установленные биты, вы должны замаскировать верхние биты изрезультат.Это делается на шаге 2.
Итак, ответ на ваш пример: представление неплавающих значений в Java является дополнением к двум, и поэтому при умном приведении значения от int к long верхние битызаполнены 1 для отрицательных чисел.Таким образом, они должны быть удалены.