考虑下面的例子:
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).
它与操作符优先级以及如何计算操作符有关。
括号'()'优先级更高,具有从左到右的结合性。
等式'=='在这个问题中是下一个,从左到右具有结合律。
赋值'='排在最后,具有从右到左的结合性。
系统使用堆栈计算表达式。表达式从左向右求值。
现在回到最初的问题:
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
首先x(1)将被压入堆栈。
然后inner (x = y)将被计算并推入值为x(3)的堆栈。
现在x(1)将与x(3)进行比较,因此结果为假。
x = 1; // reset
System.out.println((x = y) == x); // true
在这里,
(x = y)将被计算,现在x值变为3,x(3)将被推入堆栈。
现在x(3)的值改变后的等式将被推入堆栈。
现在表达式将被求值,两者将相同,因此结果为真。