有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

为什么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中使用更短的表达式


共 (3) 个答案

  1. # 1 楼答案

    I'm not sure if there is an item in the Java Language Specification that dictates loading the previous value of a variable...

    有。下次如果你不清楚说明书上写了什么,请阅读说明书,然后询问是否不清楚

    ... the right side (x = y) which, by the order implied by brackets, should be calculated first.

    这种说法是错误的括号并不表示评估顺序。在Java中,求值顺序是从左到右的,不管括号是什么。括号决定子表达式边界的位置,而不是计算顺序

    Why does the first expression evaluate to false, but the second evaluate to true?

    ==运算符的规则是:计算左侧以生成值,计算右侧以生成值,比较值,比较是表达式的值

    换句话说,expr1 == expr2的含义始终与您编写了temp1 = expr1; temp2 = expr2;然后对temp1 == temp2进行了评估一样

    左侧带有局部变量的=运算符的规则是:计算左侧以生成变量,计算右侧以生成值,执行赋值,结果是已赋值的值

    所以把它放在一起:

    x == (x = y)
    

    我们有一个比较运算符。计算左边的值——我们得到当前值x。计算右边:这是一个赋值,所以我们计算左边来产生一个变量-,变量x-,我们计算右边-,当前值y-,把它赋值给x,结果就是赋值。然后,我们将x的原始值与分配的值进行比较

    你可以做(x = y) == x作为练习。再次记住,所有计算左侧的规则都发生在所有计算右侧的规则之前

    I would have expected (x = y) to be evaluated first, and then it would compare x with itself (3) and return true.

    你的期望是基于对Java规则的一系列错误信念。希望你现在有了正确的信念,并在未来期待真实的事情

    This question is different from "order of evaluation of subexpressions in a Java expression"

    这句话是假的。这个问题完全是密不可分的

    x is definitely not a 'subexpression' here.

    这种说法也是错误的。在每个例子中,它是一个子表达式两次

    It needs to be loaded for the comparison rather than to be 'evaluated'.

    我不知道这意味着什么

    显然你还有很多错误的信念。我的建议是,你阅读说明书,直到你的错误信念被真正的信念所取代

    The question is Java-specific and the expression x == (x = y), unlike far-fetched impractical constructs commonly crafted for tricky interview questions, came from a real project.

    这句话的出处与问题无关。规范中明确描述了此类表达的规则;读吧

    It was supposed to be a one-line replacement for the compare-and-replace idiom

    既然这一行的替换给你这个代码的读者造成了很大的困惑,我认为这是一个糟糕的选择。让代码更简洁但更难理解并不是一种胜利。这不太可能让代码更快

    顺便说一句,C#将比较和替换作为一种库方法,可以下放到机器指令中。我相信Java没有这样的方法,因为它不能在Java类型系统中表示

  2. # 3 楼答案

    正如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
    

    请注意,无论xy的初始值如何,第二个值的计算结果始终为true,因为您正在有效地将一个值的赋值与它被赋值的变量进行比较,并且a = bb按该顺序计算的值在定义上始终相同