考虑下面的例子:

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中应该有更短的表达式。


当前回答

左边的第二个比较很简单,在把y赋值给x之后(在左边),你就比较3 == 3。在第一个例子中,你比较x = 1和新赋值x = 3。似乎总有一个当前状态从左到右读取x的语句。

其他回答

左边的第二个比较很简单,在把y赋值给x之后(在左边),你就比较3 == 3。在第一个例子中,你比较x = 1和新赋值x = 3。似乎总有一个当前状态从左到右读取x的语句。

正如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的赋值顺序总是相同的。

表达式从左到右求值。在这种情况下:

int x = 1;
int y = 3;

x == (x = y)) // false
x ==    t

- left x = 1
- let t = (x = y) => x = 3
- x == (x = y)
  x == t
  1 == 3 //false

(x = y) == x); // true
   t    == x

- left (x = y) => x = 3
           t    =      3 
-  (x = y) == x
-     t    == x
-     3    == 3 //true

这里的问题是算术运算符/关系运算符在两个运算符中的优先顺序= vs =占主导地位的是==(关系运算符占主导地位),因为它在=赋值运算符之前。 不管优先级,求值的顺序是LTR(从左到右)优先级在求值顺序之后。 因此,不考虑任何约束条件,求值就是LTR。

==是一个二进制相等运算符。

二进制操作符的左操作数似乎在右操作数的任何部分被求值之前就已经完全求值了。 Java 11规范>求值顺序>首先求左操作数