【问题标题】:Confusion about compound assingnments (+=, -=, *=, ...) in Java关于 Java 中的复合赋值(+=、-=、*=、...)的困惑
【发布时间】:2018-04-10 20:32:56
【问题描述】:

我对以下代码的结果有点困惑:

    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 |

我在这里缺少什么?谁能给我解释一下这是怎么回事?

谢谢!

【问题讨论】:

  • 可能需要从 JLS 的角度来回答,假设它定义明确。但是像这样的异国情调的表达没有实际用途。

标签: java primitive integer-arithmetic compound-assignment


【解决方案1】:

JLS 15.26.2 表示关注,https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.26.2

如果左侧操作数表达式不是数组访问表达式,则:

首先,计算左侧操作数以产生一个变量。如果这个求值突然完成,那么赋值表达式出于同样的原因突然完成;不计算右侧操作数,也不进行赋值。

否则,将保存左侧操作数的值,然后计算右侧操作数。如果这个求值突然完成,那么赋值表达式也会因为同样的原因而突然完成并且不会发生赋值。

否则,左侧变量的保存值和右侧操作数的值用于执行复合赋值运算符指示的二元运算。如果这个操作突然完成,那么赋值表达式出于同样的原因突然完成并且没有赋值发生。

否则,二元运算的结果将转换为左侧变量的类型,经过值集转换(第 5.1.13 节)到适当的标准值集(不是扩展指数值集),并将转换的结果存储到变量中。

所以x的原始值,即1,被保存,然后RHS被评估。因此它是-3

【讨论】:

    【解决方案2】:

    与其他一些语言不同(看看你,C++),Java 语言规范保证expression operands are evaluated left-to-right:

    Java 编程语言保证运算符的操作数看起来是按照特定的计算顺序计算的,即从左到右。

    让我们展开你的复合语句:

    x -= ((x += 1) << 1);
    x = x - ((x = x + 1) << 1);
        ^
    

    首先计算带有箭头的x,这意味着表达式中稍后发生的赋值不会影响该值(在这种情况下,JVM 堆栈上已经有一个1)。其余的评估按照您的预期进行,但最终的操作是1 - 4 = -3

    请注意,在上述声明之后,JLS 还包含一个绝对适用于此处的注释:

    建议代码不要过度依赖本规范。当每个表达式最多包含一个副作用(作为其最外层操作)时,代码通常会更清晰,并且当代码不完全依赖于表达式的从左到右求值导致的异常时。 p>

    【讨论】:

    • @txmns 乐于助人。如果您发现一个答案有帮助,您可以使用左侧的箭头对其进行投票;您可以为您认为有用的答案投票。我看到您找到了“接受”按钮,这是您认为最好或最有帮助的答案。
    【解决方案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,因为赋值运算符返回的值与分配给变量的值相同。

    【讨论】:

      【解决方案4】:
      x -= ((x += 1) << 1);
      x = x - ((x += 1) << 1);
        = 1 - ((1 + 1) << 1);
        = 1 - (2 << 1)
        = 1 - 4
        = -3
      

      【讨论】:

        猜你喜欢
        • 2020-09-18
        • 1970-01-01
        • 2013-04-08
        • 2019-05-12
        • 1970-01-01
        • 1970-01-01
        • 2020-12-25
        • 2020-09-22
        • 1970-01-01
        相关资源
        最近更新 更多