考虑下面的例子:
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)首先被求值,然后它将x与自身(3)进行比较并返回true。
这个问题与Java表达式中子表达式的求值顺序不同,因为x在这里肯定不是“子表达式”。它需要被加载来进行比较,而不是被“评估”。这个问题是java特有的,表达式x == (x = y)与通常为棘手的面试问题而设计的牵强的不切实际的构造不同,它来自一个真实的项目。它应该是比较-替换习惯用法的一行替换
int oldX = x;
x = y;
return oldX == y;
它比x86的CMPXCHG指令更简单,在Java中应该有更短的表达式。
如果您想编写Java编译器,或者测试程序以验证Java编译器是否正常工作,那么您提出的这类问题是一个非常好的问题。在Java中,这两个表达式必须产生您所看到的结果。例如,在c++中,它们就不需要这样做——所以如果有人在他们的Java编译器中重用了c++编译器的某些部分,理论上你可能会发现编译器没有像它应该的那样工作。
As a software developer, writing code that is readable, understandable and maintainable, both versions of your code would be considered awful. To understand what the code does, one has to know exactly how the Java language is defined. Someone who writes both Java and C++ code would shudder looking at the code. If you have to ask why a single line of code does what it does, then you should avoid that code. (I suppose and hope that the guys who answered your "why" question correctly will themselves avoid that ind of code as well).
正如LouisWasserman所说,表达式从左到右求值。java并不关心“evaluate”实际上做了什么,它只关心生成一个(非易失性的,最终的)值。
//the example values
x = 1;
y = 3;
因此,要计算System.out.println()的第一个输出,需要执行以下操作:
x == (x = y)
1 == (x = y)
1 == (x = 3) //assign 3 to x, returns 3
1 == 3
false
为了计算第二个:
(x = y) == x
(x = 3) == x //assign 3 to x, returns 3
3 == x
3 == 3
true
请注意,不管x和y的初始值如何,第二个值的值总是为true,因为您实际上是在将值的赋值与赋值的变量进行比较,并且根据定义,a = b和b的赋值顺序总是相同的。