5

以下代码打印出“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
4

7 回答 7

20

Postfix++增加 variable 的值,并返回在 increment 之前的值operator++因此,您的示例中的返回值将是1,当然1 + 2也会给出3,然后将其分配给a。在赋值时,++已经增加了ato的值2(因为有优先级),所以=覆盖了增加的值。

于 2009-09-28T21:35:21.963 回答
13

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

唯一有点令人困惑的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
  • 将 3 分配给变量a

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

  • a2在评估期间被分配到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例如)的任务。

于 2009-09-28T21:40:25.280 回答
3

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

于 2009-09-28T21:58:22.900 回答
2

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

考虑以下代码片段:

    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 编译器评估。这意味着从三个加号组合在一起,编译器假定前两个为后缀运算符,第三个为二进制加号运算符。这实际上是后缀运算符优先于其他运算符的结果。

The second code fragment shows how the outputs differ by writing the expression as z = x + ++y; which explicitly specifies which plus sign is a binary operator.

于 2014-02-22T20:45:23.980 回答
1

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

于 2009-09-28T21:35:58.470 回答
0

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

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

于 2009-09-28T21:37:04.850 回答
0

我从来没见过

 a = b + a++; 

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

int a++ = 1;

这是行不通的。

通常你会看到

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

a = 1;
a++;
a = b + a; // 4
于 2013-11-27T14:28:58.200 回答