如果 i++ ++i 写在一行里,为什么出现这个结果?

问题:为什么出现下面的结果?
代码:

int i = 0;
int a = (i++) + (i++) + (++i);
System.out.println(a); // 输出4

希望能用 javap 分析的字节码文件解释下这个输出,如果不能,那用口述也行,这是在《Java特种兵上》书第三章第二节中碰到的问题(第85页)。

阅读 4.9k
8 个回答

这几行代码对应的字节码如下(javap -c xxx.class):
(其中/**/里面的内容是我写的注释)

Code:
       0: iconst_0            /* 将常量0压入栈中 */
       1: istore_1            /* 栈顶元素出栈,存入局部变量1(即i=0) */
       2: iload_1             /* 将局部变量1取出,压入栈中(栈顶为0) */
       3: iinc          1, 1  /* 将局部变量1的值加1(注意这里是直接操作变量i,而不是操作栈.现在i=1) */
       /* 以上两步对应的是第一处的i++ */
       6: iload_1             /* 将局部变量1取出,压入栈中(栈顶为1) */
       7: iinc          1, 1  /* 将局部变量1的值加1(i=2) */
       /* 以上两步对应的是第二处的i++ */
      10: iadd                /* 取出栈顶两个元素相加,将结果压入栈中(即1+0=1) */
      11: iinc          1, 1  /* 将局部变量1的值加1(i=3) */
      14: iload_1             /* 将局部变量1取出,压入栈中 */
      /* 以上两步对应的是++i(可以看出,i++与++i的区别其实就是:i++是先入栈后加1,++i是先加1后入栈) */
      15: iadd                /* 取出栈顶两个元素相加,将结果压入栈中(即3+1=4) */
      16: istore_2            /* 栈顶元素出栈,存入局部变量2(即a=4) */
      17: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      20: iload_2             /* 取局部变量2压栈 */
      21: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      24: return

这样你就能明白了,i++下一次才会自增,而++i本次就会自增,而i会累加的

int i = 0;  // i=0
int a = (i++);  // a=0, i=1
int b = (i++);  // b=1, i=2
int c = (++i);  // c=3, i=3
System.out.println(a); 
System.out.println(b); 
System.out.println(c); 

查看结果

奉劝楼主不要研究这类问题。用如果用C语言试的话,结果是3(我试过MSVC,还没试过其他编译器)。而:

(i++) + (++i) + (++i)

这个结果是6。

务必坚持一个原则:运算符++--要独立成行
换句话说,要始终认为i++++i是一回事。如果同事的代码中有++--跟其他运算符组合用,务必改写掉,否则就留下一个坑。

这个和你用什么语言无关,造成这个原因是你的前置++后置++运算顺序的问题,

int a = (i++) + (i++) + (++i);

等效于:

    int i = 0;
    int a = 0;
    a = i++; // i = 0,a = i + a = 0, i = i+1 = 1
    a += i++; // i = 1,a = i + a = 1, i = i+1 = 2
    a += ++i; // i = i+1 = 3, a = a + i = 4

不知道你看明白了没有?

i++ 这种模式是先计算在自增
++i 这种模式是先自增在计算
所以 int a = 0 + 1 + 3

int i = 0;
int a = (i++) + (i++) + (++i);

| 执行过程 | i值 |

Image

由于不明原因的排版问题,我只能截图了?

凭感觉写了个操作数栈的执行过程,自增自减是在栈顶发生的,这类对变量自身值读-写的操作在多线程情况下存在 happend-before问题,因此并发环境下基本不会直接写自增自减,需要用到java自实现的CAS类比如 AtomicInteger

i++ 是一个表达式, 表达式的值为 i的值, 副作用是i的值 加1。
++i 是一个表达式, 表达式的值为 i + 1, 副作用是 i的值 加1

int a = (i++) + (i++) + (++i) 就是 a = 0 + 1 + 3 = 4

i++与++i其中任何一个单独写在一行中是没有区别的,如果应用到其他语句中就有区别了。前者是先使用变量的值,使用过在自增1,后者是先自增1,而后在使用新的变量值。

推荐问题