Java中的逻辑运算符优先级

4
我对此非常不满:http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.22。它明确指出:

"如果操作数表达式没有副作用,则每个运算符都是可交换的。"

"这些操作符具有不同的优先级,其中&的优先级最高,|的优先级最低。"

那么JVM为什么不遵守自己的规定呢?以以下示例为例。

public static void main(String[] args){
    boolean bool = isTrue1() | isFalse1() & isFalse2() ;
    System.out.println("Result : " + bool);
}

public static boolean isFalse1() {
    System.out.println("1 : " + false);
    return false ;
}
public static boolean isFalse2() {
    System.out.println("2 : " + false);
    return false ;
}
public static boolean isTrue1() {
    System.out.println("3 : " + true);
    return true ;
}

结果如下:
3 : true
1 : false
2 : false
Result : true

根据 & 运算符比 | 运算符具有优先级的事实,实际结果应该是:

1 : false
2 : false
3 : true
Result : true

希望解释一下为什么这个实现不正确。即使在第二部分周围添加括号,也没有使用正确的优先级。


1
什么问题?你的结果是匹配的,只是顺序不对。 - telkins
3
这些不是逻辑运算符,而是位运算符。 - user1907906
根据官方的Java规范,根据它们周围的数据,它们被称为逻辑运算符和位运算符。同时,&&和||被称为条件-与/条件-或运算符。这甚至不重要,关键是你需要查看链接的规范。 - user2890248
问题在于,当我的代码具有副作用(我在这里用一个简单的sout调用进行了演示)时,我不能依赖官方的Java规范是正确的。我正在寻求解释。 - user2890248
1
“运算符优先级”与表达式的解释方式有关;它简单地意味着 a | b & c 等同于 a | (b & c) 而不是 (a | b) & c。它与运行时部分的评估顺序无关。不幸的是,我本来想给你指出一份解释“运算符优先级”的资源,但维基百科页面的第一句话实际上让问题更加混淆了。我可能要对此提出抱怨。 - ajb
@user2890248,它们都是逻辑运算符。然而,||&&是短路运算符,而|&则不是。 - Simon Forsberg
5个回答

9
“这些运算符具有不同的优先级,& 的优先级最高,| 的优先级最低。”虽然它们的优先级更高,但并不意味着它们的操作数将首先被计算。

boolean bool = isTrue1() | isFalse1() & isFalse2() ;

变成等效于

boolean bool = isTrue1() | ( isFalse1() & isFalse2() ) ;

这就是所有优先级的含义。

正如Java语言规范所述, 运算符操作数从左到右进行评估。

Java编程语言保证运算符的操作数以特定的顺序出现,即从左到右进行评估。


3

&符号的优先级比|高,但在你的情况下,计算这个表达式:

boolean bool = isTrue1() | isFalse1() & isFalse2()

这与评估以下内容相同:

  boolean bool = (isTrue1()) | (isFalse1() & isFalse2())

这意味着,| 表达式的两侧优先级相同。在这种情况下,Java将按从左到右的顺序对它们进行评估。
首先它会调用 isTrue1(),因为它是最左边的。然后再计算第二个括号内的内容,也是按照从左到右的顺序进行计算:isFalse1() 和 isFalse2()。

1
方法的执行顺序不一定与运算符优先级相匹配;每个方法的副作用按照调用方法的顺序出现,然后它们的结果被评估以生成最终的打印语句。

0
你在这里做的是按位组合而不是逻辑运算。因此,Java 遵循左到右的顺序,正如人们所期望的那样。
如果您实际使用逻辑运算(将 | 替换为 ||,& 替换为 &&),则结果变为:
1 : true
Result : true

1
这不是最重要的区别,重要的是 ||&&短路运算符 - Simon Forsberg

-2

由于您使用的是二进制比较器(&和|)而不是逻辑比较器(&&和||),因此Java将在比较结果之前调用所有函数。


如果表达式的结果已经确定,可能不会调用所有函数 - 这被称为短路求值 - Gowtham
3
短路求值在位运算符&和|中不使用,只用于逻辑运算符&&和||。 - ajb

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