Contents

Java 编译时错误“二元运算符的操作数类型错误”

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。相反,我们对整数(i) 和 1执行按位与 (&) 运算。如果结果为 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
等于 == !=
按位与 &
按位异或 ^
按位或 OR |
逻辑与 &&
逻辑或
三元 ? :
运算赋值 = += -= *= /= %= &= ^= |= «= »= »>=

正如我们在上面的列表中看到的,**模运算符 (%) 比相等运算符 ( == )**具有更高的优先级。另一方面,**按位与运算符 (&)**在表中的等式运算符 (==) 下方。

这就是为什么“ i % 2 == 1 ”按预期工作而“ i & 1 == 1 ”没有按预期工作的原因。

我们在示例中遇到了编译时错误。因此,我们可以相对较早地发现问题。但是,想象一下某些具有运算符优先级错误的实现编译但会产生错误的结果。找到问题的真正原因可能会不必要地花费我们很多时间。

因此,值得牢记 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.