对 Java 中的复合赋值(+=、-=、*=、...)感到困惑
Confusion about compound assingnments (+=, -=, *=, ...) in Java
我对以下代码的结果有点困惑:
int x = 1;
x -= ((x += 1) << 1);
System.out.println(x);
它打印出 -3
,但我希望它打印出 -2
,因为在我的脑海中,计算应该是这样的:
| Opearation | Returned | x |
+------------+----------+---+
| int x = 1; | - | 1 |
+------------+----------+---+
| (x += 1) | 2 | 2 |
+------------+----------+---+
| (2 << 1) | 4 | 2 |
+------------+----------+---+
| x -= 4; | - |-2 |
我在这里错过了什么?有人可以向我解释一下这是怎么回事吗?
谢谢!
x -= ((x += 1) << 1);
x = x - ((x += 1) << 1);
= 1 - ((1 + 1) << 1);
= 1 - (2 << 1)
= 1 - 4
= -3
JLS 15.26.2 表示如下,https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.26.2
If the left-hand operand expression is not an array access expression, then:
First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.
所以x
的原始值,即1被保存下来,然后计算RHS。因此它是 -3
.
在处理子表达式 (x+=1) 之前,x (=1) 的值填充在表达式的 RHS 上,因此最左边的 x 在 x+=1 中处理之前被替换为 1 路,结果变成 2。因此它将是 ...
x = 1 - ((x=1+1) << 1)
x = 1 - ((x=2) << 1)
x = 1 - (2 << 1)
x = 1 - 4
x = -3
此处 x=2 结果为 2 作为赋值运算符 returns 与分配给变量的值相同。
与其他一些语言(看你,C++)不同,Java 语言规范保证 expression operands are evaluated left-to-right:
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
让我们展开你的复合语句:
x -= ((x += 1) << 1);
x = x - ((x = x + 1) << 1);
^
带箭头的 x
首先求值,这意味着表达式中稍后发生的赋值不会影响值(在这种情况下,JVM 堆栈已经有一个 1
在上面)。其余的评估如您所料进行,但最终操作是 1 - 4 = -3
.
请注意,在上述声明之后,JLS 还包括一条绝对适用于此的注释:
It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.
我对以下代码的结果有点困惑:
int x = 1;
x -= ((x += 1) << 1);
System.out.println(x);
它打印出 -3
,但我希望它打印出 -2
,因为在我的脑海中,计算应该是这样的:
| Opearation | Returned | x |
+------------+----------+---+
| int x = 1; | - | 1 |
+------------+----------+---+
| (x += 1) | 2 | 2 |
+------------+----------+---+
| (2 << 1) | 4 | 2 |
+------------+----------+---+
| x -= 4; | - |-2 |
我在这里错过了什么?有人可以向我解释一下这是怎么回事吗?
谢谢!
x -= ((x += 1) << 1);
x = x - ((x += 1) << 1);
= 1 - ((1 + 1) << 1);
= 1 - (2 << 1)
= 1 - 4
= -3
JLS 15.26.2 表示如下,https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.26.2
If the left-hand operand expression is not an array access expression, then:
First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.
所以x
的原始值,即1被保存下来,然后计算RHS。因此它是 -3
.
在处理子表达式 (x+=1) 之前,x (=1) 的值填充在表达式的 RHS 上,因此最左边的 x 在 x+=1 中处理之前被替换为 1 路,结果变成 2。因此它将是 ...
x = 1 - ((x=1+1) << 1)
x = 1 - ((x=2) << 1)
x = 1 - (2 << 1)
x = 1 - 4
x = -3
此处 x=2 结果为 2 作为赋值运算符 returns 与分配给变量的值相同。
与其他一些语言(看你,C++)不同,Java 语言规范保证 expression operands are evaluated left-to-right:
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
让我们展开你的复合语句:
x -= ((x += 1) << 1);
x = x - ((x = x + 1) << 1);
^
带箭头的 x
首先求值,这意味着表达式中稍后发生的赋值不会影响值(在这种情况下,JVM 堆栈已经有一个 1
在上面)。其余的评估如您所料进行,但最终操作是 1 - 4 = -3
.
请注意,在上述声明之后,JLS 还包括一条绝对适用于此的注释:
It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.