Влияние побитового оператора на логическое значение в Java

118

Побитовые операторы должны перемещать переменные и оперировать с ними бит за битом. В случае с целыми числами, длинными, символами это имеет смысл. Эти переменные могут содержать полный диапазон значений, зависящих от их размера.

Однако в случае логических значений логическое значение может содержать только два значения. 1 = истина или 0 = ложь. Но размер логического значения не определен. Он может быть большим, как байт, или совсем маленьким.

Итак, каков эффект использования побитового оператора для логического значения? Преобразует ли JVM его в обычный логический оператор и двигается ли дальше? Обрабатывает ли он логическое значение как одноразрядный объект для операции? Или результат не определен вместе с размером логического?

Дэниел Бингэм
источник
1
Я думаю, вы не можете использовать побитовый оператор с логическим значением. Только по номерам. Уверен ~ не выйдет, не знаю как насчет других операторов.
Martijn Courteaux
4
Вы можете использовать некоторые из них, мы только что обнаружили | используется в нашем устаревшем коде. Мы его удаляем, но этот код скомпилирован и заработал.
Дэниел Бингхэм,
9
Так как в одном происходит короткое замыкание, а в другом - нет (см. Ответ mobrule), перед изменением | к || вы можете убедиться, что последующие логические выражения не имеют побочных эффектов, которые исходный программист намеревался всегда выполнять.
John M Gant

Ответы:

122

Операторы &, ^и |являются побитовыми операторами, если операнды являются примитивными целочисленными типами. Они являются логическими операторами, когда операнды являются логическими, и их поведение в последнем случае указано. См. Подробности в разделе 15.22.2 Спецификации языка Java .

Ноэль Анг
источник
57
В частности, &, ^ и | - логические логические операторы без короткого замыкания.
Кен
14
Вот прямая ссылка на упомянутый выше раздел: docs.oracle.com/javase/specs/jls/se7/html/…
Энди Томас,
Если вышесказанное верно, почему ideone.com/oGSF7c выдает исключение с нулевым указателем? Если |=оператор был логичным, программа никогда не должна была запускать x.getValue()директиву.
ikromm 05
1
@JohnKrommidas, ваш x равен нулю, поэтому вы получаете исключение NullPointerException. Вам нужно создать его экземпляр.
Бен,
4
@Ben, как говорит @Ken, логика не замыкается, поэтому оценивается вторая часть. Так a || x.foo()что безопасно, если x равно нулю, но 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                  ||

Что это значит для тебя?

Абсолютно ничего, пока вы придерживаетесь либо only &and, |либо only &&and ||.

Но поскольку |имеет более высокий приоритет, чем &&(в отличие от ||, который имеет более низкий приоритет), их свободное смешивание может привести к неожиданному поведению.

Так 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 -|

Если вы хотите, чтобы OR имел более высокий приоритет, чем AND, вы можете использовать |и &&вместе, но это не рекомендуется.

Но вам действительно следует заключать их в скобки, чтобы прояснить приоритет при использовании разных символов, например (a && b) || c(скобки для уточнения приоритета) a && b && c(скобки не нужны).

Бернхард Баркер
источник
3

Даже если это сработает, не стоит этого делать. Спецификации языка определяют побитовые операторы только тогда, когда оба операнда имеют примитивные целочисленные типы или оба имеют логический тип. Я бы сказал, что для любого другого случая результаты не определены:

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

LeffeBrune
источник
Вопрос находится около булевы, а не о примитивов или смеси примитивов и булевы.
talonx