小编典典

为什么 x == (x = y) 与 (x = y) == x 不一样?

all

考虑以下示例:

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) 进行比较,按照括号所暗示的顺序,应首先计算右侧 ( )。

为什么第一个表达式的计算结果为false,而第二个表达式的计算结果为true?我本来希望(x = y)首先被评估,然后它会x与自身(3)比较并返回true


这个问题与 Java 表达式中子表达式的求值顺序不同,x这里绝对不是“子表达式”。需要
加载 它以进行比较而不是“评估”。x == (x = y)这个问题是特定于 Java
的,与通常为棘手的面试问题而设计的牵强附会的不切实际的结构不同,这个表达式来自一个真实的项目。它应该是比较和替换成语的单行替换

int oldX = x;
x = y;
return oldX == y;

它比 x86 CMPXCHG 指令更简单,应该在 Java 中使用更短的表达式。


阅读 108

收藏
2022-06-23

共1个答案

小编典典

按照括号中的顺序,应该首先计算

不,一个常见的误解是括号对计算或评估顺序有任何(一般)影响。它们只会将表达式的部分强制转换为特定的树,将正确的操作数绑定到作业的正确操作。

(而且,如果您不使用它们,此信息来自运算符的“优先级”和关联性,这是语言语法树定义方式的结果。事实上,当您使用时,这仍然是它的工作方式使用括号,但我们简化并说我们不依赖任何优先规则。)

一旦完成(即一旦你的代码被解析成程序),这些操作数仍然需要被评估,并且有关于如何完成的单独规则:所述规则(正如 Andrew
向我们展示的那样)声明每个操作的 LHS首先在 Java 中求值。

请注意,并非所有语言都如此;&&例如,在 C++ 中,除非您使用类似or的短路运算符,否则||操作数的评估顺序通常是未指定的,您不应该依赖它。

教师需要停止使用诸如“这使得加法首先发生”之类的误导性短语来解释运算符优先级。给定一个表达式x * y + z,正确的解释是“运算符优先级使加法发生在x * yand之间z,而不是yand之间z”,没有提及任何“顺序”。

2022-06-23