i++,++i 的底层实现原理

Demo 如下所示

    public static void main(String[] args) {
        System.out.println(Demo.method1(10));
        System.out.println(Demo.method2(10));
    }

    public static int method1(int a) {return a++;}
    public static int method2(int b) {return ++b;}

运行结果:

10
11
Process finished with exit code 0

我们通过反编译得到字节码进行分析,看到method1方法的字节码如下所示

0 iload_0
1 iinc 0 by 1
4 ireturn

为什么 a++ 之后还是返回a值呢?

       iload_0 表示的是从栈中局部变量表获取10,然后把10压入操作数栈,这个时候操作数栈中有一个值就是10,然后执行iinc 0 by 1 表示在把局部变量表中索引为0的位置值也就是我们的10, 进行加1,这个时候局部变量表中的值其实就变成了了11了,然后执行ireturn,ireturn作用是把我们在操作数栈的值或者是地址引用给出栈,这里因为我们上述的iload_0把10压入了我们的操作数栈中,所以我们的ireturn就是把我们的10弹出栈了,至此给我们System.out.println(method1(10))输出的就是10了

这里我们需要明白局部变量表和操作数栈有什么作用,大致的说下:

  • 局部变量: 故名只意,就是用来存储我们的基本类型局部变量的值,或者是存储我们的引用类型的地址引用
  • 操作数栈:方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。

这里涉及到的机器操作指令有兴趣的可以看看这个文档,google翻译即可查看指令

好了,说完了method1方法之后,应该就知道为什么a++是返回的本身了吧,其实是相当于返回了一个副本缓存

接着我们再看看method2方法字节码如下所示:

0 iinc 0 by 1
3 iload_0
4 ireturn

为什么这个++a返回的是a+1的值呢?

我们先看看System.out.println(method2(10)); 这句代码中把10传递给了method2(int a)方法,这个时候因为我们的int a是一个局部变量,所以method2方法中的a会存在索引为0的局部变量表中,值也就是传递过来的10,接着执行指令iinc 0 by 1,就是把局部变量表索引为0的值給加1,变成了11

紧接着执行iload_0指令,作用是把局部变量表索引为0的值给我压入操作数栈中,因为这个时候索引为0的局部变量值已经是11了,所以压入操作数栈中就值就是11,然后通过ireturn指令又把这个11給我弹出操作数栈了,返回给我们的System.out.prinntln()调用者了,所以输出的就是11啦

如果还是不太清楚的话,可能还是对这几个指令不熟悉而已,建议把这几个指令看明白就行了

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔道不误砍柴功

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值