为什么在此忽略此Java运算符优先级?

时间:2009-09-28 21:33:17

标签: java post-increment

以下代码打印出“3”,而不是“4”,如您所料。

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

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

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

% 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

7 个答案:

答案 0 :(得分:19)

Postfix ++增加变量的值,返回增量之前的值。因此,您示例中operator++的返回值将为1,当然1 + 2将提供3,然后将其分配给a。到分配时,++已将a的值增加到2(因为优先级),因此=会覆盖该增量值。

答案 1 :(得分:13)

此处不会忽略运算符优先级。

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

  1. 它会增加一个
  2. 应用的变​​量
  3. 它的返回值等于增加之前变量的值
  4. 因此,如果a包含1且b在此行之前的值为2,则

    a = b + a++;
    

    然后发生以下步骤:

    • 评估b
      • 表达式b的值为2,因此请记住值2
    • 评估a++
      • 表达式a++的值为1,因此请记住值1
      • 将变量a中的值增加1,因此它现在保持值2
    • 添加两个表达式的结果(分别为2和1)
    • 2 + 1 = 3
    • 将3分配给变量a

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

      在评估a 期间,
    • 2被分配到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)的任务。

答案 2 :(得分:3)

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

答案 3 :(得分:2)

我对此运算符优先级定义(如定义here)有同样的问题,我认为上述回复都没有完全解释和澄清此定义中的悖论。 这就是我认为postfix运算符对其他运算符(在本例中为binary plus运算符)的更高优先级意味着。

考虑以下代码片段:

    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;来显示输出的不同,它明确指定哪个加号是二元运算符。

答案 4 :(得分:1)

这不是优先事项,而是运营商定义的问题。 根据定义后缀运算符在封闭表达式中使用变量后执行。

答案 5 :(得分:0)

postfix ++运算符所说的是:

在任何等式中使用变量的原始值,然后在之后递增变量。

答案 6 :(得分:0)

我从未见过

 a = b + a++; 

正在使用,它让我觉得编码不好。像我那样使用它也意味着你可以写:

int a++ = 1;

哪个不起作用。

通常你会看到

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

a = 1;
a++;
a = b + a; // 4