int j=0; for(int i=0;i<100;i++) j=j++; System.out.println(j); 如果你运行一下上面的程序,就会发现它打印的结果居然是0,但是如果把j=j++换成j++的话就会打印100.这是为什么呢? 如果你稍微有一点经验就会知道i++与++i的区别: i++是在所有其他操作完成之后,自身加1。 ++i是在自身加1之后,再去完成其他操作。 为什么++放在前面和后面区别这么大呢? 让我们从字节码的角度看看是怎么回事儿吧! 首先在这之前我们应该对java的栈有一点了解。 在jvm中有这么一个数据结构叫java栈,当线程启动的时候,会分配一块内存当做该线程的栈,每个栈由一系列的栈帧组成。每个栈帧对应一个方法,当线程执行方法时,就是栈帧出栈,入栈的过程。 每个栈帧包含三部分数据:本地变量(参数+方法内的变量)、操作数栈和其他数据,本文主要涉及本地变量和操作数栈。 先看看i++的实现: public static void main(String[] args){ int i=0; i=i++; } 编译之后的字节码如下:
public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1,locals=2,args_size=1 0:iconst_0 //把数值0 push到操作数栈 1:istore_1 //把操作数栈写回到本地变量第2个位置 2:iload_1 //把本地变量第2个位置的值push到操作数栈 3:iinc 1,1 //把本地变量表第2个位置加1 6:istore_1 //把操作数据栈写回本地变量第2个位置 7:return LineNumberTable:可以发现变量a在执行iinc的时候已经变成1了,但是istore_1又把变量a所在位置覆盖成0,所以执行完i=i++,i还是原来那个值。
另外,来看下++i的实现:
public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1,locals=2,args_size=1 0:iconst_0 //把数值0 push到操作数栈 1:istore_1 //把操作数栈写回到本地变量第2个位置 2:iinc 1,1 //把本地变量表第2个位置加1 3:iload_1 //把本地变量第2个位置的值push到操作数栈 6:istore_1 //把操作数据栈写回本地变量第2个位置 7:return LineNumberTable: line 16:0 line 17:2 line 18:7整个过程实现如下 和i++不同的地方在于,在变量进入操作数栈之前,就先执行了iinc指令,所以进入操作数的值是加1后的值,最后写回的值也是最新值。