Wpływ operatora bitowego na wartość logiczną w Javie

118

Operatory bitowe mają przemieszczać zmienne i operować na nich bit po bicie. W przypadku liczb całkowitych, długich i znaków ma to sens. Te zmienne mogą zawierać pełen zakres wartości wymuszonych przez ich rozmiar.

Jednak w przypadku logicznych wartości logicznych może zawierać tylko dwie wartości. 1 = prawda lub 0 = fałsz. Ale rozmiar logicznej nie jest zdefiniowany. Może być tak duży jak bajt lub mały.

Więc jaki jest efekt użycia operatora bitowego na boolowskim? Czy wirtualna maszyna Java zasadniczo przekłada to na normalnego operatora logicznego i idzie dalej? Czy na potrzeby operacji traktuje wartość logiczną jako jednostkę jednobitową? A może wynik jest niezdefiniowany wraz z rozmiarem wartości logicznej?

Daniel Bingham
źródło
1
Myślę, że nie można użyć operatora bitowego na boolowskim. Tylko na liczbach. Jestem pewien, że ~ nie zadziała, nie wiem co z innymi operatorami.
Martijn Courteaux
4
Możesz użyć niektórych z nich, właśnie odkryliśmy | używane w naszym starym kodzie. Usuwamy go, ale ten kod został skompilowany i działał.
Daniel Bingham
9
Ponieważ jeden powoduje zwarcie, a drugi nie (zobacz odpowiedź mobrule), zanim zmienisz | do || możesz chcieć się upewnić, że kolejne wyrażenia boolowskie nie mają żadnych skutków ubocznych, które pierwotny programista zamierzał zawsze wykonywać.
John M Gant

Odpowiedzi:

122

Operatory &, ^i |są operatorami bitowymi, gdy operandy są pierwotnymi typami całkowitymi. Są operatorami logicznymi, gdy operandy są logiczne, a ich zachowanie w tym drugim przypadku jest określone. Szczegółowe informacje zawiera sekcja 15.22.2 specyfikacji języka Java .

Noel Ang
źródło
57
W szczególności & oraz ^ i | są logicznymi operatorami logicznymi bez zwarć.
Ken
14
Oto bezpośredni link do sekcji wspomnianej powyżej: docs.oracle.com/javase/specs/jls/se7/html/ ...
Andy Thomas,
Jeśli powyższe jest prawdziwe, dlaczego ideone.com/oGSF7c zgłasza wyjątek wskaźnika zerowego? Jeśli |=operator był logiczny, program nigdy nie powinien był uruchamiać x.getValue()dyrektywy.
ikromm
1
@JohnKrommidas, twoje x jest zerowe, dlatego otrzymujesz wyjątek NullPointerException. Musisz go utworzyć.
Ben
4
@Ben, jak mówi @Ken, logika nie powoduje zwarcia, więc druga część jest oceniana. Więc a || x.foo()jest bezpieczne, jeśli x jest zerowe, ale a | x.foo()nie jest. |=przestrzega tych samych zasad, co |.
Michael Smith
86

Użycie operatora bitowego może obejść zachowanie polegające na zwarciu:

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

Jeśli booleanExpression1()ocenia false,
booleanExpression2()to nie jest oceniany w pierwszym przypadku i
booleanExpression2()(i wszelkie skutki uboczne, jakie może mieć) jest oceniany w drugim przypadku,

tłum
źródło
2
A operacja bitowa przebiega zwykle szybciej niż operacja zwarciowa (pod warunkiem, że ocena jest prosta)
rds
1
Bitowe &będzie szybsze, ale wywołanie drugiej funkcji można zignorować za pomocą&&
NatNgs
20

Poza tym, co zostało omówione w innych odpowiedziach, warto to zauważyć &&i ||mieć inny priorytet niż &i |.

Wyciąg z tabeli priorytetów (z najwyższym priorytetem na górze).

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

Co to dla ciebie oznacza?

Absolutnie nic, o ile trzymasz się tylko &i |lub tylko &&i ||.

Ale ponieważ |ma wyższy priorytet niż &&(w przeciwieństwie do ||, który ma niższy priorytet), ich swobodne mieszanie może prowadzić do nieoczekiwanego zachowania.

Więc a && b | c && dto to samo a && (b | c) && d,
w przeciwieństwie do tego, a && b || c && dktóre byłoby (a && b) || (c && d).

Aby udowodnić, że to nie to samo, rozważ wyciąg z tabeli prawdy:

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 -|

Jeśli chcesz lub mają wyższy priorytet niż I, mogłyby korzystać |i &&razem, ale nie jest to zalecane.

Ale naprawdę powinieneś umieścić je w nawiasach, aby wyjaśnić pierwszeństwo za każdym razem, gdy używasz różnych symboli, tj. (a && b) || c(Nawiasy wyjaśniające pierwszeństwo), a && b && c(nie są potrzebne nawiasy).

Bernhard Barker
źródło
3

Nawet jeśli to zadziała, nie powinieneś tego robić. Specyfikacje języka definiują operatory bitowe tylko wtedy, gdy oba operandy są typu pierwotnych liczb całkowitych lub oba są typu boolowskiego. Powiedziałbym, że dla każdego innego przypadku wyniki nie są zdefiniowane:

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

LeffeBrune
źródło
Pytanie jest o wartości logiczne, a nie o prymitywów lub mieszanką prymitywów i logicznych.
talonx