Вплив оператора побітових операцій на логічний оператор на Java


118

Побітові оператори повинні подорожувати змінні та оперувати ними побітно. У випадку цілих чисел, довгих, знаків це має сенс. Ці змінні можуть містити повний діапазон значень, накладених на їх розмір.

Що стосується булевих, то булевий може містити лише два значення. 1 = вірно або 0 = хибно. Але розмір булева не визначений. Він може бути великим, як байт або маленьким трохи.

Отже, який ефект від використання розрядного оператора на булевому? По суті, JVM переводить його на звичайний логічний оператор і рухається далі? Чи розглядає це булеве значення як єдине розрядне ціле з метою операції? Або результат не визначений разом із розміром булевого?


1
Я думаю, що ти не можеш використовувати побітовий оператор на булі. Тільки на числах. Я впевнений, що ~ не буде працювати, я не знаю, що з іншими операторами.
Мартійн Курто

4
Ви можете використовувати деякі з них, ми щойно відкрили | використовується в нашому застарілому коді. Ми його видаляємо, але цей код складено та працює.
Даніель Бінгем

9
Оскільки один має коротке замикання, а інший - ні (див. Відповідь мобруле), перш ніж змінити | до || Ви можете переконатися, що наступні булеві вирази не мають жодних побічних ефектів, які початковий програміст завжди мав виконувати.
Джон М Гант

Відповіді:


122

Оператори &, ^і |побітові оператори, коли операнди є примітивними інтегральними типами. Вони є логічними операторами, коли операнди булеві, а їх поведінка в останньому випадку уточнюється. Докладніше див. Розділ 15.22.2 Специфікації мови Java .


57
Зокрема, & і ^ і | є логічними булевими операторами без короткого замикання.
Кен

14
Ось пряме посилання на згаданий вище розділ: docs.oracle.com/javase/specs/jls/se7/html/…
Енді Томас

Якщо вищезазначене вірно, чому ideone.com/oGSF7c викидає нульовий вказівник? Якщо |=оператор був логічним, програма ніколи не повинна запускати x.getValue()директиву.
ikromm

1
@JohnKrommidas, ваш x є нульовим, тому ви отримуєте NullPointerException. Вам потрібно інстанціювати це.
Бен

4
@Ben, як говорить @Ken, логіка не є короткою ланцюгом, тому друга частина оцінюється. Так що a || x.foo()безпечно, якщо х є нульовим, але a | x.foo()це не так. |=дотримується тих же правил, що і |.
Майкл Сміт

86

Використання бітового оператора може обійти поведінку короткого замикання:

boolean b = booleanExpression1() && booleanExpression2();
boolean b = booleanExpression1() & booleanExpression2();

Якщо має booleanExpression1()значення false, то
booleanExpression2()не оцінює в першому випадку, і
booleanExpression2()(і незалежно від побічних ефектів може бути) буде оцінюватися в другому випадку,


2
А побітна операція виконується, як правило, швидше, ніж коротке замикання (за умови, що оцінка проста)
rds

1
Побітна &швидкість буде швидшою, але виклик другої функції можна буде проігнорувати із застосуванням&&
NatNgs

20

Крім того , що розглядається в інших відповідях, варто відзначити , що &&і ||мають свої пріоритети від &і |.

Витяг із таблиці пріоритетів (з найвищим пріоритетом вгорі).

bitwise AND                 &
bitwise exclusive OR        ^
bitwise inclusive OR        |
logical AND                 &&
logical OR                  ||

Що це означає для вас?

Абсолютно нічого, доки ти дотримуєшся лише &і |тільки, &&і лише ||.

Але, оскільки |має більшу перевагу, ніж &&(на відміну від ||, яка має нижчий пріоритет), вільне змішування їх може призвести до несподіваної поведінки.

Так a && b | c && dце те саме a && (b | c) && d,
на відміну від того, a && b || c && dщо було б (a && b) || (c && d).

Щоб довести, що вони не однакові, розгляньте витяг із таблиці правди:

a | b | c | d | (b|c) | (a&&b) | (c&&d) | a && (b|c) && d | (a&&b) || (c&&d)
F | T | T | T |   T   |   F    |    T   |         F       |        T
                                                  ^                ^
                                                  |- not the same -|

Якщо ви хочете, щоб АБО мали вищий пріоритет порівняно з AND, ви можете використовувати |та &&разом, але це не рекомендується.

Але ви дійсно повинні ставити їх у дужки, щоб уточнити перевагу кожного разу, коли використовуєте різні символи, тобто (a && b) || c(дужки для уточнення переваги), a && b && c(дужки не потрібні).


3

Навіть якщо це спрацює, ви не повинні цього робити. Мовні специфікації визначають побітові оператори лише тоді, коли обидва операнди мають примітивні цілочисельні типи або обидва булевого типу. Я б сказав, що для будь-якого іншого випадку результати не визначені:

http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228


Питання знаходиться близько булеві, а нема про примітивів або суміші примітивів і булеві.
талонкс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.