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

以下代码打印出“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."":()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 

Postfix ++增加变量的值,并返回增量前的值 。 因此,示例中operator++的返回值将为1 ,当然1 + 2将给出3 ,然后将其分配给a 。 到分配时, ++已经将a的值增加到2 (因为优先级),所以=覆盖递增的值。

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

关于a++的唯一有点混乱的事情是postfix ++运算符有两个不同的效果:

  1. 它增加了它应用的变量
  2. 它的返回值等于变量增加的值

因此,如果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++期间,将2分配给a
  • 作为分配的结果,将3分配给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 (aka "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 (aka "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-4行简单地实现

 int a=1, b=2; 

第4-10行实现

 a = b + a++; 

我已经遗漏了其他线路,因为那里没有任何有趣的事情发生了。

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

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

我对此运算符优先级定义(如此处定义)有同样的问题,我认为上述回复都没有完全解释和澄清此定义中的悖论。 这就是我认为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; 有两种可能的评估,将被评估为z = x++ + y; 通过java编译器。 这意味着从三个加号组合在一起,编译器将前两个作为后缀运算符,第三个作为二进制加运算符。 事实上,这是后缀运算符优先于其他运算符的结果。

第二个代码片段通过将表达式写为z = x + ++y;显示输出如何不同z = x + ++y; 其中明确指定哪个加号是二元运算符。

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

postfix ++运算符所说的是:

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

我从来没见过

  a = b + a++; 

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

 int a++ = 1; 

这不起作用。

通常你会看到

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