Тобі, напевно, знайоме слово “біт”. Якщо ж ні, давай познайомимося з ним:) Біт - мінімальна одиниця виміру інформації в комп'ютері. Його назва походить від англійської " binary digit " - "двійкове число". Біт може бути виражений одним із двох чисел: 1 або 0. Існує спеціальна система числення, заснована на одиницях та нулях - двійкова. Не заглиблюватимемося в нетрі математики і відзначимо лише, що будь-яке число в Java можна конвертувати в його двійкову форму. Для цього потрібно використовувати класи-обгортки. Наприклад, ось як можна зробити це для числа
Усі операції виконуються ліворуч, проте з урахуванням свого пріоритету. Наприклад, якщо ми пишемо:
int
:
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(Integer.toBinaryString(x));
}
}
Виведення в консоль:
101010110
1010 10110 (я додав пробіл для зручності читання) - це число 342 у двійковій системі. Ми фактично розділабо це число на окремі біти – нулі та одиниці. Саме з ними ми можемо виконувати операції, що називаються побітовими.
-
~
- Побітовий оператор "НЕ".
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 на 2 111111111 << 3
. 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 = 2
boolean x = 6 - 2 > 3 && 12*12 <= 119;
-
12*12 = 144
boolean x = 6 - 2 > 3 && 144 <= 119;
-
6-2 = 4
boolean x = 4 > 3 && 144 <= 119;
-
Далі будуть виконані оператори порівняння:
4 > 3 = true
boolean x = true && 144 <= 119;
-
144 <= 119 = false
boolean x = true && false;
-
І, нарешті, останнім буде виконано оператор "І"
&&
.boolean x = true && false;
boolean x = false;
Оператор складання (
+
), наприклад, має вищий пріоритет, ніж оператор порівняння!=
(“не дорівнює”);Тому у виразі:
boolean x = 7 != 6+1;
спочатку буде виконано операцію 6+1, потім перевірку 7!=7 (false), а в кінці — привласнення результату
false
змінноїx
. У присвоювання взагалі найменший пріоритет із усіх операцій — подивися у таблиці.
- Логічні оператори - лекція JavaRush про логічні операції. Ми до них ще нескоро дійдемо, але почитати можна вже зараз, не буде шкоди
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ