在学 jvm 之前,我也认为 i++ 与 ++i 的区别就是 一个先使用 i 的值,再自增;一个先自增,再使用 i 的值。直到我遇到了 i = i++ 。
int i = 10; i = i++; System.out.println(i);
按照正常逻辑,先把 i 的值赋给 i 本身,此时 i 为10;然后再执行自增,最后的结果应该是 11 。
不出意外的话就该出意外了,当我输入这段代码,按下执行的时候,得到的 i 的值却是 10,而并非 11。
我也有问过一些老师,得到的答案是:i++ 就等同于 i=i+1;然后再用 i 去接收,就等同于 i=i=i++,这种写法是错误的,而且实际开发也不可能这样写。
显然,这并不能说服我。
网上有一种说法是:
JVM 在处理 i=i++ 时,会建立一个临时变量来接收 i++ 的值 , 然后返回这个临时变量的值 , 返回的值再被等号左边的变量接收了 , 这样就是说 i 虽然自增了但是又被赋为原来的值 , 这样输出的结果自然就是 10 了。
也就等同如下代码:
int i = 0; int temp = i;
i++;
i=temp System.out.println(i);
这样虽然可以解释清楚为什么 i=i++ 不会改变 i 的值,但是对于追求底层原理的人来说,显然还是有存在被质疑的点,就只是跟你说会用一个零食变量保存 i 的值,似乎还是没有告诉你到底为什么会这样。
然后,只能去看编译之后的字节码指令。
这里需要先了解:
- java虚拟机中,一个方法被调用时,会在虚拟机栈里压入一个栈帧,方法执行完之后,栈帧弹出;
- 每一个栈帧又包括 局部变量表、操作数栈 等一些其他的东西;
- 局部变量表用于保存方法用到的局部变量,操作数栈用于对变量的一些操作;
知道了这些,就可以看字节码指令了。
通过 javac -v 文件名 就可以查看class文件的字节码指令,或者在 idea 中安装 jclass lib 插件,就可以直接查看字节码指令。
对应的字节码指令为:
0 bipush 10 2 istore_1 3 iload_1 4 iinc 1 by 1 7 istore_1 8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;> 11 iload_1 12 invokevirtual #3 <java/io/PrintStream.println : (I)V> 15 return
然后,在网上搜索每个字节码表示的意思,就可以得到对应的解释。
0 bipush 10 // 将10压入操作数栈中 2 istore_1 // 将操作数栈中的10弹出,放在局部变量表序号为1的位置 3 iload_1 // 从局部变量表中加载序号为1的变量(10),压入操作数栈中 4 iinc 1 by 1 // 将局部变量表中序号为1的变量的值加一 7 istore_1 // 将操作数栈中的10弹出,放在局部变量表序号为1的位置 8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;> 11 iload_1 // 从局部变量表中加载序号为1的变量,用于输出打印 12 invokevirtual #3 <java/io/PrintStream.println : (I)V> 15 return
大致过程为,先从 局部变量表 中加载变量 i 到 操作数栈 ,然后对局部变量表中的 i 进行自增操作,最后再将操作数栈中的 i 返回给 局部变量表。这就解释了为什么执行了 i=i++ 之后,并没有改变 i 的值,同时验证了第一种解释,用一个临时变量保存 i 的值,然后 i 自增后再把临时变量的值返回给 i 。这里所说的保存 i 的值得临时变量就对应着 操作数栈。
个人想法:
操作数栈,顾名思义,应该堆变量进行操作的地方,自增不就是对数的一种操作,那为什么是直接在局部变量表中进行自增操作,反而操作数栈只是起到了一个 “暂时保存” 数据的地方。
不过仔细想,如果将自增操作放在操作数栈中进行的话,要想实现原本 i++ 先使用 i 的值再自增的效果就会更复杂一点,需要对局部变量表中的 i 进行两次压入栈的操作,上面的 i 用于使用 i 的值,等使用完之后弹出,先入栈的 i 在进行自增操作。
其实我感觉这个后自增,就有点像数据库中的脏读,也就是事务A读取了 i=10;然后事务B修改了 i=11,这个时候事务A有又将自己知道的 i=10赋值给数据库中。通常使用 i++ 时,在刚读取了局部变量表中的 i 的值后,i 的值就被修改了。也就是我们使用的 i 是脏数据(自增之前的数据)。
标签:10,操作数,字节,++,局部变量,自增,原理,变量 From: https://www.cnblogs.com/simply820/p/16871864.html