字节码层面理解java中i++和++i的区别-创新互联

还是让我们从一道面试题说起吧,代码如下,你知道方法执行最后会输出什么吗?

10年积累的做网站、成都网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先建设网站后付款的网站建设流程,更有石门免费网站建设让你可以放心的选择与我们合作。

public static void main(String[] args) {

int i = 0;

for (int j = 0; j < 50; j++) {

i = i++;

}

System.out.println(i);

}

不卖关子,最后输出结果是0,而不是50,不知道跟你的认知是否一致。

直接上字节码,让我们从字节码层面看看i++背后的逻辑。

public static void main(java.lang.String[]);

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=3, args_size=1

0: iconst_0

1: istore_1

2: iconst_0

3: istore_2

4: iload_2

5: bipush 50

7: if_icmpge 21

10: iload_1

11: iinc 1, 1

14: istore_1

15: iinc 2, 1

18: goto 4

21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

24: iload_1

25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V

28: return

先抛出这个方法局部变量表

0  1  2

args  i  j

pc 0~1两个指令,为下标为1的局部变量赋值为0,也就是局部变量i

pc 2~3两个指令,为下表为2的局部变量赋值为0,也就是局部变量j

pc 4~7三个指令,取局部变量j的值与50比较,如果j>=50,跳转到pc=21的指令处,如果不满足则顺序往下执行

pc 10~14三个指令,是i=i++这行代码编译后的指令。在jvm中,局部变量表和操作数栈是两个不同的存储数据的内存区域。iload_1表示将局部变量表中下标为1的变量,也就是变量i的值复制一份,加载到操作数栈顶,innc 1,1 指令则将局部变量表中变量i的值加1再写回局部变量表中变量i的位置,istore_1则将栈顶的数据覆盖局部变量表中变量i的位置,所以执行完这3个命令后,变量i的值并没有发生变化。用伪代码来表示这三个指令的逻辑就是这样

int stack_top = local_variable[1];//把下标为1的局部变量加载到栈顶

local_variable[1] = local_variable[1] + 1;//下标为1的局部变量自增1

local_variable[1] = stack_top;//用栈顶的值覆盖下标为1的局部变量

pc 15指令iinc 2,1 将变量j自增1

pc 18指令goto 4,程序重新从pc=4的地方开始执行

pc 21~25三个指令,就是打印下标为1的局部变量,也就是打印变量i

所以,从pc10~14三个指令,可以看出变量i=i++这行代码不会改变变量i的值,因此最后打印结果是0。

如果将 i=i++ 改成 i=++i,结果会是怎样呢?

public static void main(String[] args) {

int i = 0;郑州好的妇科医院 http://www.zzkedayy.com/

for (int j = 0; j < 50; j++) {

i = ++i;

}

System.out.println(i);

}

输出结果是50,还是直接看字节码

public static void main(java.lang.String[]);

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=3, args_size=1

0: iconst_0

1: istore_1

2: iconst_0

3: istore_2

4: iload_2

5: bipush 50

7: if_icmpge 21

10: iinc 1, 1

13: iload_1

14: istore_1

15: iinc 2, 1

18: goto 4

21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

24: iload_1

25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V

28: return

除了指令10~14,对应的代码就是 i=++i,其他部分跟上面的字节码指令一样,所以我们只看不一样的部分。

pc 10 innc 1,1 这里先执行自增指令,将下标为1的局部变量i的值自增1

pc 13 iload_1 将下标为1的局部变量i的值加载到操作数栈顶

pc 14istore_1 将操作数栈顶的值覆盖下标为1的局部变量i的值

用伪代码来表示这段逻辑就是这样

local_variable[1] = local_variable[1] + 1;//下标为1的局部变量自增1

int stack_top = local_variable[1];//把下标为1的局部变量加载到栈顶

local_variable[1] = stack_top;//用栈顶的值覆盖下标为1的局部变量

所以,从pc10~14三个指令,可以看出变量 i=++i 这行代码会使i的值增加1,因此最后打印结果是50。

与i++对应的指令不同的地方是,++i会先执行innc 1,1指令,这条指令会是i的值增加1,然后再参与计算。而i++会先将i的值保存到另外一个地方,然后再对i自增1,但是i=i++的赋值(也就是=)会用已保存的i的旧值覆盖i的新值,所以i=i++,i的值并不会变。

总结:讲解了i=i++和i=++i的字节码底层原理。

不知道朋友你理解了没有,试试这道题输出结果是什么

int i = 0;

int result = i++ + ++i + i++;

System.out.println(result);

创新互联www.cdcxhl.cn,专业提供香港、美国云服务器,动态BGP最优骨干路由自动选择,持续稳定高效的网络助力业务部署。公司持有工信部办法的idc、isp许可证, 机房独有T级流量清洗系统配攻击溯源,准确进行流量调度,确保服务器高可用性。佳节活动现已开启,新人活动云服务器买多久送多久。


网页名称:字节码层面理解java中i++和++i的区别-创新互联
分享地址:http://pwwzsj.com/article/edjsp.html