字节码分析 i=i++; 的结果

之前看到过一个这样的问题:

 int i = 0;
 i = i++;
 System.out.println(i);

问最后的输出的结果为多少?
答案其实一直都知道,但是说透原因,好像又有一点模棱两可,今天仔细看了看这段代码的编译后的代码,解释如下:

首先贴上相关字节码:

  0: iconst_0
  1: istore_1
  2: iload_1
  3: iinc 1, 1
  6: istore_1
  7: getstatic     #2           // Field java/lang/System.out:Ljava/io/PrintStream;
  10: iload_1
  11: invokevirtual #3       // Method java/io/PrintStream.println:(I)V

要分析上述代码,首先需要简要了解一下java栈帧的结构以及指令的具体含义:

1. Java栈帧

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机里面从入栈到出栈的过程。栈帧存储了方法的局部变量表,操作数栈,动态链接和方法返回值等信息。
(1)局部变量表
局部变量表用于存放方法参数和方法内定义的局部变量,是一组变量存储空间(类似于数组结构,可通过索引随机访问,若为成员方法,则索引0位置一般存储方法所属对象的实例引用,this)。
局部变量表以变量槽(slot)为最小单位,变量槽可存放byte,short,char,int,boolean,float,reference和returnAddress共八种。
(2)操作数栈
和局部变量表一样,操作数栈也是被组织成一个以字长为单位的数组,但是操作方式有所不同。操作数栈不同过索引随机访问,而是通过标准的栈操作(压栈和出栈)来访问的

2. 指令

方法中的局部变量存储在局部变量表中,但涉及变量等的计算时,则需要将局部变量表中存储的值,读入操作栈中,从而使虚拟机解释执行引擎对这些数进行运算。
这里主要介绍上面字节码中的两个主要指令:iload,istore。加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输。(如果将进行运算等操作需要入栈,将局部变量表中的数据入栈加载入操作数栈中,在操作数栈中运算完毕再将结果出栈存储到局部变量表中)

了解了这些知识点之后,我们就可以来分析字节码了:

 iconst_0	// 将常量0入栈
 istore_1   // 操作数栈出栈,将出栈的元素存到局部变量表索引为1的slot里;这里和上面一条指令合在一起 为 int i = 0;这句的操作。
 iload_1    // 从局部变量表索引为1的slot中读取数值,存入操作数栈中(入栈)
 iinc 1, 1  // 将局部变量表索引为1的slot中的数值,加一
 istore_1   //  将栈顶元素出栈,存入局部变量表索引为1的slot中,这一步将覆盖原先经过iinc 1, 1操作后,slot1为2的值

.

结论:

从上面可以看出 i++本质上做了两步操作:a. 将局部变量表中的变量值入栈 (即先使用)b. 将局部变量表中该变量的值加一(即后自增,自增操作直接在局部变量表中完成);而表达式中的赋值操作是在操作数栈中进行的,然后将结果存入被复制变量在局部变量表中的位置,因此会覆盖原先的自增操作的结果。

小弟才疏学浅,有误之处还烦请各位大佬指出~

.

参考资料:
栈帧结构:https://www.iteye.com/blog/wangwengcn-1622195
字节码指令:https://blog.csdn.net/itcats_cn/article/details/81113647

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值