1. 概述
Java提供了一套位运算符。这些运算符使我们能够方便地操作数字的单个位。
然而,在比较位运算的结果时,我们可能会遇到一个常见的陷阱。
在这个简短的教程中,我们将讨论为什么我们可能会遇到Java编译时错误“二元运算符的无效操作数类型”,以及如何解决这个问题。
2. 问题介绍
如常,我们将通过一个例子来理解这个问题。但首先,让我们看看一个简单的方法:
public void checkNumber() {
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
intList.forEach(i -> {
if (i & 1 == 1) {
System.out.println(i + " is odd.");
} else {
System.out.println(i + " is even.");
}
});
}
我们可以看到,checkNumber
方法遍历intList
,检查并输出每个数字是奇数还是偶数。
需要注意的是,方法中的奇数检查逻辑并没有使用常见的方式:i % 2 == 1
。相反,我们在Integer
类型的数i
上执行位与(&)操作。如果结果是1,我们知道整数i
是奇数:i & 1 == 1
。
然而,当我们尝试测试上面的方法时,代码出乎意料地无法编译:
java: bad operand types for binary operator '&'
first type: java.lang.Integer
second type: boolean
接下来,让我们理解问题的原因并学习如何解决。
3. 理解Java运算符优先级
首先,错误消息相当直接。它指出我们试图对boolean
类型和Integer
类型进行位与运算。
然而,这很奇怪,因为我们确实写了"i & 1"
在代码中。为什么编译器认为boolean
类型参与了位与运算?
这是因为“*==”运算符的优先级高于“&”运算符。也就是说,“i & 1 == 1”等同于“i & (1 == 1)”。因此,我们有“i & true (boolean)*”。
现在,我们可能问:“好吧,==的优先级高于*&*。但是为什么i % 2 == 1
能得到预期的结果呢?”
为了回答这个问题,我们需要更深入地了解Java运算符的优先级规则。
Java提供了许多运算符。在实践中,我们经常一起使用不同的运算符。因此,理解Java运算符的优先级至关重要。否则,我们可能会得到意想不到的结果。
接下来,让我们看看Java运算符的优先级规则(表中的运算符越靠前,其优先级越高):
运算符
优先级
后缀
expr++ expr--
一元
++expr –expr +expr -expr ~ !
乘法
* / %
加法
+ –
移位
<< >> >>>
关系
< > <= >= instanceof
相等
== !=
位与
&
异或
^
与或
|
逻辑与
&&
逻辑或
||
三元
? :
赋值
= += -= *= /= %= &= ^= |= <<= >>= >>>=
如列表所示,*取模运算符()的优先级高于相等运算符(==)。另一方面,位与运算符(&)在表中的优先级低于相等运算符(==)**。
这就是为什么i % 2 == 1
能得到预期结果,而i & 1 == 1
却不能。
我们的示例中遇到了编译时错误。所以,我们可以在早期阶段检测到问题。但是,想象一下,如果带有运算符优先级bug的实现编译通过,但产生了错误的结果,找到问题的真实原因可能会无谓地花费大量时间。
因此,记住Java运算符的优先级规则是值得的。
4. 解决问题
现在我们理解了问题的原因,解决问题并不困难。我们只需要在位与运算上添加括号:
if (i & 1 == 1) --> if ((i & 1) == 1)
修复后,如果我们再次运行方法,我们会发现编译器不再抱怨,并收到预期的输出:
1 is odd.
2 is even.
3 is odd.
4 is even.
5 is odd.
6 is even.
7 is odd.
5. 总结
在这篇简短的文章中,我们通过一个位与运算的例子分析了“二元运算符的无效操作数类型”的编译错误。
此外,我们讨论了Java运算符的优先级规则。
最后,我们解决了问题。