Java中按位运算符对布尔值的影响

134

位运算符用于对变量进行逐位操作。对于整数、长整数和字符,这是有意义的。这些变量可以包含其大小所强制的完整值范围。

然而,在布尔值的情况下,布尔值只能包含两个值。1 = true或0 = false。但是布尔值的大小没有定义。它可以像一个字节那样大,也可以像一个比特那样小。

那么,在布尔值上使用位运算符有什么效果呢?JVM是否将其转换为普通的逻辑运算符并继续执行?它是否将布尔值视为单个比特实体以用于运算?还是结果未定义,就像布尔值的大小一样?


1
我认为你不能在布尔值上使用位运算符,只能在数字上使用。我确定 ~ 不起作用,其他运算符我不知道。 - Martijn Courteaux
4
你可以使用其中一些,我们刚刚在我们的旧代码中发现了一个竖线符号并正在将其删除,但是这段代码已经编译并且工作正常。 - Daniel Bingham
9
因为其中一个是短路计算,而另一个不是(请参考mobrule的回答),所以在将“|”改为“||”之前,您可能需要确保后续的布尔表达式没有任何副作用,这些副作用原来的程序员打算始终执行。 - John M Gant
4个回答

136

当操作数为基本整型时,运算符 &, ^, 和 | 是按位运算符。当操作数为布尔值时,它们是逻辑运算符,并且其行为在这种情况下是指定的。请参阅Java语言规范第15.22.2节以获取详细信息。


71
具体来说,&、^和|是非短路逻辑布尔运算符。 - Ken
如果以上内容是正确的,为什么http://ideone.com/oGSF7c会抛出空指针异常?如果`|=`运算符是逻辑的,程序就不应该运行`x.getValue()`指令。 - ikromm
1
@JohnKrommidas,你的x是空的,这就是为什么你会得到一个NullPointerException。你需要实例化它。 - Ben
@Ben,这就是整个问题的关键。如果操作是按位的,虚拟机就不必费心去检查语句的第二部分。既然它确实检查了它,那么这个操作就不可能是按位的。 - ikromm
5
@Ben,正如@Ken所说,逻辑运算不是短路运算,因此第二部分会被计算。因此,如果x为null,则a || x.foo()是安全的,但a | x.foo()则不安全。|=遵循与|相同的规则。 - Michael Smith

97

使用位运算符可以规避短路行为:

boolean b = booleanExpression1() && booleanExpression2();
boolean b = booleanExpression1() & booleanExpression2();
如果booleanExpression1()的计算结果为false,则在第一种情况下不会评估booleanExpression2(),而在第二种情况下将评估booleanExpression2()(及其可能有的任何副作用)。

2
位运算通常比短路运算(如果评估简单)执行得更快。 - rds
1
按位与&会更快,但使用&&可以忽略对第二个函数的调用。 - NatNgs

25

除了其他答案中涵盖的内容外,值得注意的是&&||&|具有不同的优先级。

摘自优先级表(优先级最高的在顶部)。

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

这对你意味着什么?

只要你坚持只使用&|或者只使用&&||,那就没有任何问题。

但是,由于|的优先级高于&&(与||相反,其优先级较低),自由混合它们可能会导致意外行为。

因此,a && b | c && da && (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(不需要括号)。

4

这个问题是关于布尔值的,而不是关于原始类型或原始类型和布尔值混合的。 - talonx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接