【问题标题】:Why is this Java operator precedence being ignored here?为什么这里忽略了这个 Java 运算符优先级?
【发布时间】:2010-12-02 03:33:22
【问题描述】:

以下代码打印出“3”,而不是您可能期望的“4”。

public class Foo2 {
    public static void main(String[] args) {
        int a=1, b=2;             
        a = b + a++;
        System.out.println(a);
    } 
}

我明白怎么做。后缀增量发生在加载“a”的值之后。 (见下文)。

我不太明白为什么。后缀++的运算符优先级高于+所以不应该先执行吗?

% javap -c Foo2

Compiled from "Foo2.java"
public class Foo2 extends java.lang.Object{
public Foo2();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iconst_2
   3:   istore_2
   4:   iload_2
   5:   iload_1
   6:   iinc    1, 1
   9:   iadd
   10:  istore_1
   11:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   14:  iload_1
   15:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   18:  return

【问题讨论】:

    标签: java post-increment


    【解决方案1】:

    后缀++ 增加变量的值,返回增加之前的值。因此,在您的示例中operator++ 的返回值将是1,当然1 + 2 将给出3,然后将其分配给a。在分配时,++ 已经将a 的值增加到2(由于优先级),所以= 会覆盖增加的值。

    【讨论】:

    • 我见过的关于先例主题的最佳解释。
    【解决方案2】:

    这里没有忽略运算符优先级。

    关于a++ 唯一有点令人困惑的是,后缀++ 运算符有两个不同的效果:

    1. 它将应用的变量增加一
    2. 它的返回值等于变量之前它增加的值

    所以如果a 在此行之前有 1 并且b 有值 2:

    a = b + a++;
    

    然后发生以下步骤:

    • 评估b
      • 表达式 b 的值为 2,因此请记住值 2
    • 评估a++
      • 表达式 a++ 的值为 1,因此请记住值 1
      • 将变量a 中的值加一,现在它的值是2
    • 将两个表达式的结果相加(分别为2和1)
    • 2 + 1 = 3
    • 为变量a赋值3

    如您所见,代码有效地将两个值分配给a

    • 2 在评估a++ 期间分配给a
    • 3 作为分配的结果分配给a

    由于第二个赋值发生在第一个之后,您只能看到第二个的效果,并且您将始终观察到 a 在该行之后的值为 3。

    编辑:我将尝试提供对反编译代码的解释。这可能有点难以理解,除非您知道 JVM 在内部是如何工作的(即您知道 JVM 是如何成为基于堆栈的 VM 以及这意味着什么):

       // Push the constant 1 on the stack
       0:   iconst_1
       // Pop the topmost value from the stack (1) and store it in the local variable #1 (a.k.a "a")
       1:   istore_1
       // Push the constant 2 on the stack
       2:   iconst_2
       // Pop the topmost value from the stack (2) and store it in the local variable #2 (a.k.a "b")
       3:   istore_2
       // Load the local variable #2 ("b") and push its value (2) on the stack
       4:   iload_2
       // Load the local variable #1 ("a") and push its value (1) on the stack
       5:   iload_1
       // Increment the local variable #1 by 1 (this action does not use the stack!)
       6:   iinc    1, 1
       // Pop the 2 topmost values from the stack (2 and 1), add them and push the result (3) back on the stack
       9:   iadd
       // Pop the topmost value from the stack (3) and store it in local variable #1 ("a")
       10:  istore_1
    

    0-3 行简单实现

    int a=1, b=2;
    

    第 4-10 行实现

    a = b + a++;
    

    我已经省略了其他行,因为那里不再发生任何有趣的事情了。

    作为一个有趣的旁注:很明显,这段代码根本没有优化。原因是优化是 Java 世界中运行时环境(即 JVM)的任务,而不是编译器的任务(例如javac)。

    【讨论】:

      【解决方案3】:

      后增量/减量运算符 (a++) 返回增量之前的值。前增量/减量 (++a) 返回增量后的值。

      【讨论】:

        【解决方案4】:

        我对这个运算符优先级定义(定义为here)有同样的问题,我认为以上答复都没有准确解释和澄清这个定义中的悖论。 这就是我认为后缀运算符对其他运算符(在本例中为二进制加运算符)的更高优先级的含义。

        考虑以下代码片段:

            int x = 1, y =4 , z;
            z = x+++y;  // evaluates as: x++ + y
            System.out.println("z : " + z); // z: 5
            System.out.println("y : " + y); // y: 4
            System.out.println("x : " + x); // x: 2
        
            x = 1; y =4 ; 
            z = x + ++y;
            System.out.println("z : " + z); // z: 6
            System.out.println("y : " + y); // y: 5
            System.out.println("x : " + x); // x: 1
        

        如您所见,一个表达式z = x+++y; 有两个可能的求值,Java 编译器将求值为z = x++ + y;。这意味着从三个加号组合在一起,编译器假定前两个为后缀运算符,第三个为二进制加号运算符。 这实际上是后缀运算符优先于其他运算符的结果。

        第二个代码片段通过将表达式编写为z = x + ++y; 来显示输出的不同之处,该表达式明确指定哪个加号是二元运算符。

        【讨论】:

          【解决方案5】:

          这不是优先级的问题,而是运算符定义的问题。 根据定义后缀运算符在变量用于封闭表达式后执行。

          【讨论】:

            【解决方案6】:

            后缀 ++ 运算符的意思是:

            在任何方程中使用变量的原始值,然后增加变量。

            【讨论】:

              【解决方案7】:

              没见过

               a = b + a++; 
              

              在使用中,我觉得它是糟糕的编码。我认为这样使用它也意味着你可以写:

              int a++ = 1;
              

              这不起作用。

              通常你会看到

              int a = 1;
              int b = 2;
              a = b + a; // 3
              
              a = 1;
              a++;
              a = b + a; // 4
              

              【讨论】:

                猜你喜欢
                • 2015-05-23
                • 2017-08-15
                • 2021-10-19
                • 2017-10-13
                • 2020-11-03
                • 2023-03-11
                • 2012-12-13
                • 2014-09-09
                相关资源
                最近更新 更多