为什么i=i++后,i的值不变(深入解析)

在Java中,运行以下代码:

1         int i=10;
2         i=i++;
3         System.out.println(i);

得到的结果仍然为10,为什么呢?理论上,运算的过程不应该是i首先把10取出来,赋值给i,然后i再自增1,结果不该是11吗?

原因还是要从反编译得到的汇编源码看起。在cmd窗口,输入命令javap -c Demo(Demo是class的文件名),可以得到反编译的汇编源码,

下面我们一步步来,先将两行简单的代码反编译一下。

1         int i=10;
2         int j=9;

上述两行代码的反编译结果是

1        0: bipush        10      //将常量10压入操作数栈 
2        2: istore_1                  //将操作数栈顶元素(10)弹出,存入局部变量位置1处
3        3: bipush        9           //将常量9压入操作数栈
4        5: istore_2                  //将操作数栈顶元素(9)弹出,存入局部变量位置2处
5        6: return

上下代码可以很简单的对应起来,可以初步看出,赋值语句在汇编其实是有两步,第一步压栈(操作数栈),第二部(出栈并存储至局部变量处)。

为了进行验证,再多加一行代码,如下

1         int i=10;
2         int j=9;
3         j=i;

同样,反编译看汇编如下:

1        0: bipush        10
2        2: istore_1
3        3: bipush        9
4        5: istore_2
5        6: iload_1
6        7: istore_2
7        8: return

很明显的可以看到,j=i这一句,并不是直接把局部变量位置1的值赋值给局部变量2,而是先压入操作数栈,再弹出存储在局部变量位置2处!

下面我们把最开头的i=i++进行一下反编译,得到的结果如下。

 1 public class Demo {
 2   public Demo();
 3     Code:
 4        0: aload_0
 5        1: invokespecial #1                  // Method java/lang/Object."<init>":()V
 6        4: return
 7 
 8   public static void main(java.lang.String[]);
 9     Code:
10        0: bipush        10           //将常量10压入操作数栈
11        2: istore_1                   //将操作数的栈顶元素(10)出栈,存入局部变量表1的位置处(这两句话完成了i=10的赋值操作)
12        3: iload_1                    //将局部变量表1位置的值压入操作数栈
13        4: iinc          1, 1         //局部变量表1位置的值自增1
14        7: istore_1            //重新将操作数栈顶的值(10)出栈存入局部变量表1的位置处
15        8: return
16 }

只需要从第10行看起就可以了。

可以很明显的看到,自增过程是发生在压栈和出栈中间,所以最后出栈的值会把自增的结果覆盖,导致自增其实是没有作用的。

其实还可以得出一个结论,就是自增和普通的运算的步骤是不同的。自增是直接在局部变量区加1,而运算要进行压栈和出栈操作。

为了验证这句最关键的话,我们把下面代码进行一次反编译。

1         int i=10;
2         i++;
3         i=i+1;

得到的反编译结果如下:

1        0: bipush        10
2        2: istore_1
3        3: iinc          1, 1
4        6: iload_1
5        7: iconst_1
6        8: iadd
7        9: istore_1
8       10: return

这下很明显了,i++就只有一句话,iinc    1,1,代表在局部变量位置1处的值自增1,而i=i+1则是先把局部变量1位置处的值压栈,再把常量1压栈,再相加出栈,一共四句话!

因此,从内存的角度来看,i=i+1和i++是不同的,也就是说:

i=i++这句话与i=i=i++是不等价的!!!

明白了这个道理,我想再看这个题应该就没有那么恶心了!

 

posted @ 2018-04-01 11:09  豪杰杰杰  阅读(1533)  评论(0编辑  收藏  举报