从字节码角度彻底搞懂i++、++i操作

先来了解几个字节码指令

public static void main(String[] args) {
    int a = 10;
    int b = Short.MAX_VALUE + 1;
    int c = a + b;
}

通过javap -v 来反编译上述的字节码文件,长这样:
在这里插入图片描述

这里locals大小也就是我们局部变量表的大小。

用图解的方式逐条分析:

  1. bipush 10:将一个btye数值压入操作数栈中;(其长度会补齐 4 个字节)
    在这里插入图片描述

其它相似的指令:

  • sipush:将short压入操作数栈,其长度会补齐 4 个字节;
  • idc:将int压入操作数栈;
  • idc2_w:将long压入操作数栈,分两次压入,因为long是8个字节;
  • 当int为:-1~5时,采用iconst压入操作数栈。
  1. istore_1:将操作数栈顶的数值弹出,保存到局部变量表为1的槽中;
    在这里插入图片描述

  2. idc #3:将常量池中#3的数据压入操作数栈;
    在这里插入图片描述

低于short最大大小的数值会直接存放在方法区中,超过short最大大小的数值会被存放到运行时常量池中,如上图所示。

  1. istore_2:将操作数栈顶数据弹出到局部变量表为2的卡槽中;
    在这里插入图片描述
  2. iload_1:将局部变量表卡槽1中的数据加载到操作数栈中;
    在这里插入图片描述
  3. iload_2:同上;
    在这里插入图片描述
  4. iadd:将操作数栈中的数值相加;
    在这里插入图片描述
  5. istore_3:弹出栈顶数据到局部变量表中;
    在这里插入图片描述

分析i++ 与 ++i

下面代码中,i和b的结果应该很容易猜出。

public static void main(String[] args) {
    int i = 3;
    int b = i ++ + ++i + i--;
    // i = 4, b = 13
}

还是先来反编译看一下其字节码指令的执行流程:
在这里插入图片描述

想要理解i ++ 和 ++i,核心点就是 iload和iinc指令的执行顺序:

  • i++:先load,再iinc;
  • ++i:先innc,再load。

innc [局部变量表卡槽位置] [增加或减少的数值]

分析:

  1. iconst_3
    在这里插入图片描述
  2. istore_1
    在这里插入图片描述
  3. iload_1
    在这里插入图片描述
  4. iinc 1,1:将当前局部变量表中卡槽为1的数值加1
    在这里插入图片描述

注意,这里直接在局部变量表中做的自增操作,而我们操作数栈中的数值没有变化,还是3,上述的两步操作也就是i++的操作,先进行load操作,再innc自增。

  1. innc 1,1
    在这里插入图片描述
  2. iload_1
    在这里插入图片描述

上述两步对应的就是++i的步骤,再进行iinc操作,再load进操作数栈。

  1. iadd
    在这里插入图片描述
  2. iload_1
    在这里插入图片描述
  3. iinc 1,-1:将当前局部变量表卡槽为1的数据-1
    在这里插入图片描述
  4. iadd
    在这里插入图片描述
  5. istore_2
    在这里插入图片描述

因为所以的运算操作都是再我们的操作数栈中完成的,而++操作都是直接再局部变量表中进行的,所以load、iinc的执行顺序的不同,就导致了i++和++i的的差异。

思考题

int i = 0;
for (int j = 0; j < 10; j++) {
    i = i++;
}
System.out.println(i);	// 0
  • i++:先将i加载到操作数栈,此时i=0;随后在局部变量表中自增i,此时i在局部变量表中的值为1,操作数栈还是0;
  • i = i++:将操作数栈顶的i弹出,保存到局部变量i的卡槽中,于是原本局部变量表中i的值为2,但在这一步,又被赋值为0了。
  • 循环这种操作,最后i=0。

++i 结果就不一样了

int i = 0;
for (int j = 0; j < 10; j++) {
    i = ++i;
}
System.out.println(i);	// 10
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值