i++与++i字节码分析

最近碰到几道关于i++与++i相关的题,我们从字节码角度来分析执行情况,该文章需要读者有字节码相关基础及了解方法调用机制。

分析

下面是一个题,请问下面代码输出什么?

public static void f() {
int i = 1;
System.out.println(i++ + i++);
}

答案是3。相信有小伙伴会回答2,有此想法的是不了解其运算过程。

我们用javap -c Test.class先反编译下这个类,找到这个方法的字节码,如下所示:

public static void f();
Code:
0: iconst_1
1: istore_0
2: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
5: iload_0
6: iinc 0, 1
9: iload_0
10: iinc 0, 1
13: iadd
14: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
17: return

忽略2: getstatic14: invokevirtual这两个调用输出的指令,我们来分析下其他相关指令:

image

从图可以看出 在第一个i++之前,已经将数据从局部变量表加载到操作数栈了,如下指令:

5: iload_0
6: iinc 0, 1

6: iinc 执行完之后,局部变量表0位置的数改为2,然后第二个i++操作同样是这样操作的,先将局部变量表第0个位置的数加载到操作数栈,由于第一个i++已经将其改为2,此时再读取时,就是2。

操作数栈此时栈的元素为2,1。然后执行iadd指令,将栈顶两int型数值相加并将结果压入栈顶,此时栈顶元素就是3。进而输出3。

最后执行return,结束。

涉及到的字节码指令:

iconst

当int取值-1~5时,JVM采用iconst指令将常量压入操作数栈中
int 取值 0~5 时,JVM采用 iconst_0、iconst_1、iconst_2、iconst_3、iconst_4、iconst_5指令将常量压入操作数栈中;

取值-1时,采用iconst_m1指令将常量压入操作数栈中。

当int取值 -128~127 时,JVM采用 bipush 指令将常量压入操作数栈中。

iload

将一个局部变量加载到操作数栈
• 非静态方法:从iload_1开始的,默认第iload_0是this
• 静态方法:从iload_0开始的

istore

将一个数值从操作数栈存储到局部变量表
istore_n,n代表局部变量表第几个位置,从0开始。

iadd

将栈顶两int型数值相加并将结果压入栈顶

return

从当前方法返回,void


title: i++与++i字节码分析
author: Mingshan
tags: JVM
categories: [JVM, Bytecode]
date: 2021-06-01

posted @   mingshan  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示