Побитовые операции в Java работают с отдельными битами числа в его двоичном виде. Основных операторов шесть:
Например, вот как можно сделать это для числа
А теперь мы, в прямом смысле слова, берем каждый из наших битов и сдвигаем влево на 3 ячейки:
Вот что у нас получилось. Как видишь, все наши биты сдвинулись, а из-за пределов диапазона добавились еще 3 нуля. 3, потому что мы делали сдвиг на 3. Если бы мы сдвигали на 10, добавилось бы 10 нулей.
Таким образом, выражение
Естественно, в десятичной системе ему соответствует 0.
Простое правило для запоминания сдвигов влево:
При каждом сдвиге влево выполняется умножение числа на 2.
Например, попробуем без картинок с битами посчитать результат выражения
![Число 64 в двоичном виде перед сдвигом вправо]()
В результате сдвига на 2 вправо два крайних нуля нашего числа вышли за пределы диапазона и затерлись. У нас получилось число 10000, которому в десятичной системе соответствует число 16
Вывод в консоль:
Все операции выполняются слева направо, однако с учетом своего приоритета.
Например, если мы пишем:
~ (НЕ, инвертирует биты), & (И), | (ИЛИ), ^ (исключающее ИЛИ, XOR), а также сдвиги битов << (влево, равно умножению на 2) и >> (вправо, равно делению на 2).
Тебе наверняка знакомо слово "бит". Если же нет, давай познакомимся с ним :)Кратко
- Побитовые операции работают с отдельными битами числа (нулями и единицами двоичной формы).
~(НЕ) инвертирует все биты;&(И) дает 1, только если оба бита равны 1.|(ИЛИ) дает 1, если хотя бы один бит равен 1;^(XOR) дает 1, только если биты разные.<<сдвигает биты влево и равносилен умножению на 2 за каждый сдвиг.>>сдвигает биты вправо и равносилен делению на 2 (остаток отбрасывается).- Перевести число в двоичный вид можно методом
Integer.toBinaryString().
Например, вот как можно сделать это для числа int:
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(Integer.toBinaryString(x));
}
}
Вывод в консоль:
101010110
1010 10110 (я добавил пробел для удобства чтения) это число 342 в двоичной системе.
Мы фактически разделили это число на отдельные биты, нули и единицы. Именно с ними мы можем выполнять операции, которые называются побитовыми.
Вот все побитовые операторы Java в одной таблице:
| Оператор | Название | Что делает |
|---|---|---|
~ | НЕ (NOT) | инвертирует каждый бит: 0 меняет на 1, 1 на 0 |
& | И (AND) | бит равен 1, только если оба бита равны 1 |
| | ИЛИ (OR) | бит равен 1, если хотя бы один из битов равен 1 |
^ | исключающее ИЛИ (XOR) | бит равен 1, только если биты разные |
<< | сдвиг влево | сдвигает биты влево, равно умножению на 2 за каждый сдвиг |
>> | сдвиг вправо | сдвигает биты вправо, равно делению на 2 за каждый сдвиг |
Побитовые операторы: НЕ, И, ИЛИ, XOR
~побитовый оператор "НЕ".
00000000 00000000 00000001 01010110 число 342 в переменной типа int в java
11111111 11111111 11111110 10101001 результат выражения ~342 в java
Попробуем выполнить это на практике:
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(Integer.toBinaryString(~x));
}
}
Вывод в консоль:
11111111111111111111111010101001
&побитовый оператор "И"
&&).
Оператор &&, как ты помнишь, возвращает true только если оба операнда являются истинными. Побитовый & работает схожим образом: он сравнивает два числа по битам. Результатом этого сравнения является третье число.
Для примера, возьмем числа 277 и 432:
100010101 число 277 в двоичной форме
110110000 число 432 в двоичной форме
Далее оператор & сравнивает первый бит верхнего числа с первым битом нижнего. Поскольку это оператор "И", то результат будет равен 1 только в том случае, если оба бита равны 1. Во всех остальных случаях результатом будет 0.
100010101
&
110110000
_______________
100010000 результат работы &
Мы сравниваем сначала первые биты двух чисел друг с другом, потом вторые биты, третьи и т.д.
Как видишь, только в двух случаях оба бита в числах были равны 1 (первый и пятый по счету биты). Результатом всех остальных сравнений стал 0. Поэтому в итоге у нас получилось число 100010000. В десятичной системе ему соответствует число 272. Давай проверим:
public class Main {
public static void main(String[] args) {
System.out.println(277&432);
}
}
Вывод в консоль:
272
|побитовое "ИЛИ". Принцип работы тот же, сравниваем два числа по битам. Только теперь если хотя бы один из битов равен 1, результат будет равен 1. Посмотрим на тех же числах, 277 и 432:
|
110110000
_______________
110110101 результат работы |
Здесь уже результат другой: нулями остались только те биты, которые в обоих числах были нулями.
Результат работы это число 110110101. В десятичной системе ему соответствует число 437.
Проверим:
public class Main {
public static void main(String[] args) {
System.out.println(277|432);
}
}
Вывод в консоль:
437
Мы все посчитали верно! :)
^побитовое исключающее "ИЛИ" (также известно как XOR)
true, если хотя бы один операнд является истинным. Но не обязательно один, если оба будут true, то и результат true.
А вот исключающее "или" возвращает true только если один из операндов является истинным.
Если истинны оба операнда, обычное "или" вернет true ("хотя бы один истинный"), а вот исключающее или вернет false. Поэтому он и называется исключающим.
Зная принцип предыдущих побитовых операций, ты наверняка и сам сможешь легко выполнить операцию 277^432.
Но давай лучше лишний раз разберемся вместе :)
100010101
^
110110000
_______________
010100101 результат работы ^
Вот и наш результат. Те биты, которые были в обоих числах одинаковыми, вернули 0 (не сработала формула "один из"). А вот те, которые образовывали пару 0-1 или 1-0, в итоге превратились в единицу.
В результате мы получили число 010100101. В десятичной системе ему соответствует число 165.
Давай посмотрим, правильно ли мы посчитали:
public class Main {
public static void main(String[] args) {
System.out.println(277^432);
}
}
Вывод в консоль:
165
Супер! Все именно так, как мы и думали :)
Теперь самое время познакомиться с операциями, которые называют битовыми сдвигами.
Название, в принципе, говорит само за себя. Мы возьмем какое-то число и будем двигать его биты влево и вправо :) Давай посмотрим как это выглядит:
Сдвиг влево
Сдвиг битов влево обозначается знаком<<
Пример:
public class Main {
public static void main(String[] args) {
int x = 64;//значение
int y = 3;//количество
int z = (x << y);
System.out.println(Integer.toBinaryString(x));
System.out.println(Integer.toBinaryString(z));
}
}
В этом примере число x=64 называется значением. Именно его биты мы будем сдвигать. Сдвигать биты мы будем влево (это можно определить по направлению знака <<)
В двоичной системе число 64 = 1000000
Число y=3 называется количеством. Количество отвечает на вопрос "на сколько бит вправо/влево нужно сдвинуть биты числа x"
В нашем примере мы будем сдвигать их на 3 бита влево.
Чтобы процесс сдвига был более понятен, посмотрим на картинке.
У нас в примере используются числа типа int. Int'ы занимают в памяти компьютера 32 бита. Вот так выглядит наше изначальное число 64:
А теперь мы, в прямом смысле слова, берем каждый из наших битов и сдвигаем влево на 3 ячейки:
Вот что у нас получилось. Как видишь, все наши биты сдвинулись, а из-за пределов диапазона добавились еще 3 нуля. 3, потому что мы делали сдвиг на 3. Если бы мы сдвигали на 10, добавилось бы 10 нулей.
Таким образом, выражение x << y означает "сдвинуть биты числа х на y ячеек влево". Результатом нашего выражения стало число 1000000000, которое в десятичной системе равно 512.
Проверим:
public class Main {
public static void main(String[] args) {
int x = 64;//значение
int y = 3;//количество
int z = (x << y);
System.out.println(z);
}
}
Вывод в консоль:
512
Все верно!
Теоретически, биты можно сдвигать до бесконечности. Но поскольку у нас число int, в распоряжении есть всего 32 ячейки. Из них 7 уже заняты числом 64 (1000000).
Поэтому если мы сделаем, например, 27 сдвигов влево, наша единственная единица выйдет за пределы диапазона и "затрется". Останутся только нули!
public class Main {
public static void main(String[] args) {
int x = 64;//значение
int y = 26;//количество
int z = (x << y);
System.out.println(z);
}
}
Вывод в консоль:
0
Как мы и предполагали, единичка вышла за пределы 32 ячеек-битов и исчезла. У нас получилось 32-битное число, состоящее из одних нулей.
Естественно, в десятичной системе ему соответствует 0.
Простое правило для запоминания сдвигов влево:
При каждом сдвиге влево выполняется умножение числа на 2.
Например, попробуем без картинок с битами посчитать результат выражения
111111111 << 3
Нам нужно трижды умножить число 111111111 на 2. В результате у нас получается 888888888. Давай напишем код и проверим:
public class Main {
public static void main(String[] args) {
System.out.println(111111111 << 3);
}
}
Вывод в консоль:
888888888
Сдвиги вправо
Они обозначаются знаком>>.
Делают то же самое, только в другую сторону! :)
Не будем изобретать велосипед и попробуем сделать это с тем же числом int 64.
public class Main {
public static void main(String[] args) {
int x = 64;//значение
int y = 2;//количество
int z = (x >> y);
System.out.println(z);
}
}

В результате сдвига на 2 вправо два крайних нуля нашего числа вышли за пределы диапазона и затерлись. У нас получилось число 10000, которому в десятичной системе соответствует число 16
Вывод в консоль:
16
Простое правило для запоминания сдвигов вправо:
При каждом сдвиге вправо выполняется деление на два с отбрасыванием любого остатка.
Например,
35 >> 2
означает, что нам нужно 2 раза разделить 35 на 2, отбрасывая остатки
35/2 = 17 (отбросили остаток 1)
17:2 = 8 (отбросили остаток 1)
Итого, 35 >> 2 должно быть равно 8.
Проверяем:
public class Main {
public static void main(String[] args) {
System.out.println(35 >> 2);
}
}
Вывод в консоль:
8
Приоритет операций в Java
В процессе написания или чтения кода тебе часто будут попадаться выражения, в которых одновременно выполняются несколько операций. Очень важно понимать, в каком порядке они будут выполнены, иначе результат может быть неожиданным. Поскольку операций в Java много, все они были выделены в специальную таблицу:Operator Precedence
| Operators | Precedence |
|---|---|
| postfix | expr++ expr-- |
| unary | ++expr --expr +expr ~ ! |
| Multiplicative | * / % |
| additive | + - |
| shift | << >> >>> |
| relational | < > <= >= instanceof |
| equality | == != |
| bitwise AND | & |
| bitwise exclusive OR | ^ |
| bitwise inclusive OR | | |
| logical AND | && |
| logical OR | || |
| ternary | ? : |
| assignment | = += -= *= /= %= &= ^= |= <<= >>= >>>=
|
int x = 6 - 4/2;
вначале будет выполнена операция деления (4/2). Хоть она и идет второй по счету, но у нее выше приоритет.
Круглые или квадратные скобки меняют любой приоритет на максимальный. Это ты наверняка помнишь еще со школы. Например, если добавить их к выражению:
int x = (6 - 4)/2;
первым выполнится именно вычитание, поскольку оно вычисляется в скобках.
У логического оператора && приоритет довольно низкий, что видно из таблицы. Поэтому чаще всего он будет выполняться последним.
Например:
boolean x = 6 - 4/2 > 3 && 12*12 <= 119;
Это выражение будет выполняться так:
4/2 = 2boolean x = 6 - 2 > 3 && 12*12 <= 119;12*12 = 144boolean x = 6 - 2 > 3 && 144 <= 119;6-2 = 4boolean x = 4 > 3 && 144 <= 119;Далее будут выполнены операторы сравнения:
4 > 3 = trueboolean x = true && 144 <= 119;144 <= 119 = falseboolean x = true && false;И, наконец, последним, будет выполнен оператор "И"
&&.boolean x = true && false;boolean x = false;Оператор сложения (
+), например, имеет более высокий приоритет, чем оператор сравнения!=("не равно");Поэтому в выражении:
boolean x = 7 != 6+1;сначала будет выполнена операция 6+1, потом проверка 7!=7 (false), а в конце присваивание результата
falseпеременнойx. У присваивания вообще самый маленький приоритет из всех операций, посмотри в таблице.
- Логические операторы лекция JavaRush о логических операциях. Мы до них еще нескоро дойдем, но почитать можно уже сейчас, вреда не будет
Читайте также
- Логические операторы: чем логические
&&и||отличаются от побитовых. - Тернарный оператор: короткая запись условия, тоже участвует в таблице приоритетов.
Вопросы и ответы
Что такое побитовые операции в Java?
Это операции над отдельными битами числа в его двоичном виде. К ним относятся~ (НЕ), & (И), | (ИЛИ), ^ (XOR) и сдвиги битов << и >>.
Чем побитовый & отличается от логического &&?
Логический&& работает с булевыми значениями (true/false), а побитовый & сравнивает два числа бит за битом и возвращает число. Бит результата равен 1, только если оба соответствующих бита равны 1.
Что делает оператор ~?
Он инвертирует каждый бит числа: нули заменяет на единицы, а единицы на нули.Что делает сдвиг влево (<<)?
Сдвигает биты числа влево, добавляя нули справа. Каждый сдвиг влево на один бит равносилен умножению числа на 2.Что делает сдвиг вправо (>>)?
Сдвигает биты числа вправо, крайние биты отбрасываются. Каждый сдвиг вправо на один бит равносилен делению на 2 с отбрасыванием остатка.Как перевести число в двоичный вид в Java?
Использовать методInteger.toBinaryString(число): он вернет строку из нулей и единиц, представляющую это число.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ