为什么x==(x=y)和(x=y)=x不一样?
考虑下面的例子:
class Quirky {
public static void main(String[] args) {
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
x = 1; // reset
System.out.println((x = y) == x); // true
}
}
我不确定Java语言规范中是否有一项规定加载变量的前一个值,以便与右侧(x = y
)进行比较,根据括号暗示的顺序,应该首先计算右侧(x = y
)
为什么第一个表达式的值为false
,而第二个表达式的值为true
?我希望(x = y)
首先被评估,然后它将x
与自身(3
)进行比较,并返回true
这个问题与order of evaluation of subexpressions in a Java expression不同,因为x
在这里绝对不是“子表达式”。它需要加载进行比较,而不是“评估”。这个问题是特定于Java的,表达式x == (x = y)
不同于通常为棘手的面试问题精心设计的牵强、不切实际的结构,它来自一个真实的项目。它应该是比较替换成语的一行替换
int oldX = x;
x = y;
return oldX == y;
它甚至比x86 CMPXCHG指令更简单,应该在Java中使用更短的表达式
# 1 楼答案
有。下次如果你不清楚说明书上写了什么,请阅读说明书,然后询问是否不清楚
这种说法是错误的括号并不表示评估顺序。在Java中,求值顺序是从左到右的,不管括号是什么。括号决定子表达式边界的位置,而不是计算顺序
==
运算符的规则是:计算左侧以生成值,计算右侧以生成值,比较值,比较是表达式的值换句话说,
expr1 == expr2
的含义始终与您编写了temp1 = expr1; temp2 = expr2;
然后对temp1 == temp2
进行了评估一样左侧带有局部变量的
=
运算符的规则是:计算左侧以生成变量,计算右侧以生成值,执行赋值,结果是已赋值的值所以把它放在一起:
我们有一个比较运算符。计算左边的值——我们得到当前值
x
。计算右边:这是一个赋值,所以我们计算左边来产生一个变量-,变量x
-,我们计算右边-,当前值y
-,把它赋值给x
,结果就是赋值。然后,我们将x
的原始值与分配的值进行比较你可以做
(x = y) == x
作为练习。再次记住,所有计算左侧的规则都发生在所有计算右侧的规则之前你的期望是基于对Java规则的一系列错误信念。希望你现在有了正确的信念,并在未来期待真实的事情
这句话是假的。这个问题完全是密不可分的
这种说法也是错误的。在每个例子中,它是一个子表达式两次
我不知道这意味着什么
显然你还有很多错误的信念。我的建议是,你阅读说明书,直到你的错误信念被真正的信念所取代
这句话的出处与问题无关。规范中明确描述了此类表达的规则;读吧
既然这一行的替换给你这个代码的读者造成了很大的困惑,我认为这是一个糟糕的选择。让代码更简洁但更难理解并不是一种胜利。这不太可能让代码更快
顺便说一句,C#将比较和替换作为一种库方法,可以下放到机器指令中。我相信Java没有这样的方法,因为它不能在Java类型系统中表示
# 2 楼答案
==
是一个二进制equality operator# 3 楼答案
正如LouisWasserman所说,表达式是从左到右求值的。java并不关心“evaluate”实际上做了什么,它只关心生成一个(非易失的、最终的)值来处理
因此,要计算
System.out.println()
的第一个输出,需要执行以下操作:计算第二个:
请注意,无论
x
和y
的初始值如何,第二个值的计算结果始终为true,因为您正在有效地将一个值的赋值与它被赋值的变量进行比较,并且a = b
和b
按该顺序计算的值在定义上始终相同