Java如何处理表达式x = x - (x = x - 1)?

4
我刚刚测试了以下代码:
int x = 90;

x = x - (x = x - 1);
System.out.print(x);

它打印出1。

据我理解,事情按以下顺序进行:

  1. 计算并将x-1存储到内存中的临时变量中。
  2. x赋值为项目1的临时变量的结果。
  3. 然后计算x-新x的值
  4. 结果被分配给x

我不明白为什么在第2项的结果之后,我们从中减去x,但x仍然具有初始值。我错过了什么?


7
x = x - (x = x - 1); 等价于 x = 90 - (x = x - 1);,其中 x 的值被更新为 x 减去一个表达式的结果。该表达式先将 x 减去 1,然后将减去 1 后的值赋给 x,最终得到的结果是 1。因此,代码的最终结果是将 x 的值设置为 1。 - Turing85
5
@Matsemann 因为a)我太懒了,不想查找JLS参考文献(在我看来,这应该包含在一个正确的答案中); b)我相信这是stackoverflow上某个问题的重复;c)这个回答太简短了,而且我又太懒了,不想详细解释它。 - Turing85
@Turing85,如果这是一个答案,我会接受它的。 - Maksim Dmitriev
3个回答

6

来自https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

所有二元运算符(赋值运算符除外)都从左到右进行求值; 赋值运算符从右向左进行求值。

你正在执行90 - (90 - 1) => 1

不要混淆优先级和求值顺序。它们有关但不相同。


编辑

如@ruakh所指出的那样,JLS规范将其与上面的教程有所不同。

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15‌​.7.

二元运算符的左操作数在右操作数的任何部分被评估之前似乎已经完全评估。

如果运算符是复合赋值运算符(§15.26.2),则对左操作数的评估包括记住左操作数表示的变量并获取和保存该变量的值以用于隐含的二进制操作。

如果二元运算符的左操作数的评估突然完成,则似乎没有评估右操作数的任何部分。

它不是说赋值从右到左进行评估,而是将赋值视为先存储要更新的变量,然后评估该值,最后进行赋值。


1
+1,尽管我不同意引用语句。foo().bar = baz().bar将在调用baz()之前调用foo() - ruakh
@ruakh 我猜它把 .[ 视为运算符,按从左到右的顺序进行评估。 - Peter Lawrey
抱歉,我不明白你的意思。我的观点是,在赋值语句的左侧 foo().bar 在右侧 baz().bar 之前被评估。. 的细节对此并不重要。 - ruakh
@ruakh,点号(.)首先从左到右进行评估,然后是赋值从右到左。 - Peter Lawrey
我认为你误解了“从左到右评估运算符”的含义。(或者也许是我误解了。)我理解它的意思是在评估右操作数之前先评估左操作数。你是如何解释它的?(你能举一个代码片段的例子,因为赋值从右到左评估而表现出某种行为,如果它从左到右评估会有不同的行为吗?) - ruakh
1
附言:规范与我一致,即评估始终是从左到右的——赋值运算符没有例外:https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7。因此,您引用的那段话是错误的。 - ruakh

1
我们从以下内容开始:

int x = 90;
x = x - (x = x - 1);

第一个赋值运算符=的优先级较低,因此先计算右侧。
x = x - (x = x - 1) 的右侧是 x - b ,其中 b 是 (x = x - 1)。
这个右侧从左到右计算,因此变成了90-b。
然后计算 b,即 (x = x - 1)。再次看到赋值运算符优先级最低,所以它变成了 (x = 90 - 1) 或者 (x = 89)。
代入回去,我们有 90 - (x = 89),即 90 - 89,也就是 1。最后,第一个赋值运算符被计算,x 变成了 1。你会注意到另一个赋值运算符 (x = 89) 对整个操作没有影响。

1
   int x = 90;
   x = x - (x = x - 1);
   System.out.print(x);`
Here
x = 90 Goes in two section in your code.
First x=90 - , Second  (x=90-1);
Then x=90  - , x = 89 
Then x= 90 - 89
       System.out.Print(x);
that is x=1;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接