Efecto de un operador bit a bit en un booleano en Java

118

Se supone que los operadores bit a bit viajan variables y operan sobre ellas bit a bit. En el caso de enteros, largos, caracteres, esto tiene sentido. Estas variables pueden contener la gama completa de valores exigidos por su tamaño.

En el caso de los valores booleanos, sin embargo, un booleano puede contener solo dos valores. 1 = verdadero o 0 = falso. Pero el tamaño del booleano no está definido. Puede ser tan grande como un byte o tan pequeño como un bit.

Entonces, ¿cuál es el efecto de usar un operador bit a bit en un booleano? ¿La JVM esencialmente lo traduce a un operador lógico normal y sigue adelante? ¿Trata el booleano como una entidad de un solo bit para el propósito de la operación? ¿O el resultado no está definido junto con el tamaño de un booleano?

Daniel Bingham
fuente
1
Creo que no se puede utilizar un operador bit a bit en un booleano. Solo en números. Estoy seguro de que ~ no funcionará, no sé qué pasa con otros operadores.
Martijn Courteaux
4
Puede utilizar algunos de ellos, acabamos de descubrir un | utilizado en nuestro código heredado. Lo estamos eliminando, pero este código se compiló y funcionó.
Daniel Bingham
9
Dado que uno está en cortocircuito y el otro no (consulte la respuesta de mobrule), antes de cambiar el | a || es posible que desee asegurarse de que las expresiones booleanas posteriores no tengan ningún efecto secundario que el programador original pretendía ejecutar siempre.
John M Gant

Respuestas:

122

Los operadores &, ^y |son operadores bit a bit cuando los operandos son tipos integrales primitivos. Son operadores lógicos cuando los operandos son booleanos y se especifica su comportamiento en el último caso. Consulte la sección 15.22.2 de la Especificación del lenguaje Java para obtener más detalles.

Noel Ang
fuente
57
Específicamente, & y ^ y | son los operadores booleanos lógicos sin cortocircuito.
Ken
14
Aquí hay un enlace directo a la sección mencionada anteriormente: docs.oracle.com/javase/specs/jls/se7/html/…
Andy Thomas
Si lo anterior es cierto, ¿por qué ideone.com/oGSF7c lanza una excepción de puntero nulo? Si el |=operador era lógico, el programa nunca debería haber ejecutado la x.getValue()directiva.
ikromm
1
@JohnKrommidas, su x es nulo, por lo que obtiene una NullPointerException. Necesitas instanciarlo.
Ben
4
@Ben, como dice @Ken, la lógica no es de cortocircuito, por lo que se evalúa la segunda parte. Entonces, a || x.foo()es seguro si x es nulo, pero a | x.foo()no lo es. |=sigue las mismas reglas que |.
Michael Smith
86

El uso del operador bit a bit puede evitar el comportamiento de cortocircuito:

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

Si booleanExpression1()evalúa a false, entonces
booleanExpression2()no se evalúa en el primer caso y
booleanExpression2()(y los efectos secundarios que pueda tener) se evalúa en el segundo caso,

multitud
fuente
2
Y la operación bit a bit se realiza generalmente más rápido que la de cortocircuito (siempre que la evaluación sea simple)
rds
1
El bit &a bit será más rápido, pero la llamada a la segunda función podría ignorarse con el uso de&&
NatNgs
20

Más allá de lo que está cubierto en las otras respuestas, vale la pena señalar que &&y ||tienen precedencia diferente de &y |.

Extracto de la tabla de precedencia (con mayor precedencia en la parte superior).

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

¿Qué significa esto para ti?

Absolutamente nada, siempre y cuando te ciñas a solo &y |o solo &&y ||.

Pero, dado que |tiene una mayor precendencia que &&(a diferencia de ||, que tiene una menor precedencia), mezclarlos libremente podría conducir a un comportamiento inesperado.

Entonces a && b | c && des lo mismo que a && (b | c) && d,
en contraposición a lo a && b || c && dque sería (a && b) || (c && d).

Para demostrar que no son iguales, considere un extracto de la tabla de verdad:

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

Si desea que OR tenga mayor precedencia que AND, puede usar |y &&juntos, pero esto no se recomienda.

Pero realmente debería ponerlos entre corchetes para aclarar la precedencia siempre que use diferentes símbolos, es decir (a && b) || c(corchetes para aclarar la precedencia), a && b && c(no se necesitan corchetes).

Bernhard Barker
fuente
3

Incluso si funciona, no debería hacerlo. Las especificaciones del lenguaje definen operadores bit a bit solo cuando ambos operandos son de tipo entero primitivo o ambos son de tipo booleano. Diría que para cualquier otro caso los resultados no están definidos:

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

LeffeBrune
fuente
La pregunta es sobre booleanos, no sobre primitivos o una mezcla de primitivos y booleanos.
talonx