java有意思的程序_Java 有趣的程序编译

今天看到一道题,很有意思,特此记录一下。

public class Test {

public static void main(String args[]) {

int a = 0;

int b = 0;

while(a < 10){

b = b++;

a++;

}

System.out.println(b);

}

}

大脑编译一下,直觉告诉我每次循环b都加了两次,但总觉得哪里不对,运行出来发现结果是0,也让我百思不得其解,于是又一顿疯狂搜索学习,最后弄明白了原理,遂写一篇博客,让有兴趣的都可以看看。

上面这个代码用断点debug能看到每次循环b都是0,并没有自增,但断点并不能告诉我们为什么,只有用反汇编的手段才能把它彻底弄明白。不过在看反汇编的代码前,先弄明白什么是局部变量表、什么是操作数栈比较好。

JVM虚拟机作为提供java程序的运行环境,它在运行时,其内存被划分为了几大板块:程序计数器、虚拟机栈、本地方法栈、堆、方法区

我们要了解的局部变量表和操作数栈都是属于虚拟机栈模块,其它模块有兴趣的自行学习吧,我也不甚精通。

虚拟机栈模块中,有一个很重要的数据结构叫做“栈帧”,你可以把它理解为虚拟机栈中的其中一个栈元素,每个栈帧包含了四个东西:局部变量表、操作数栈、动态链接、返回地址

局部变量表用于存储方法中的局部变量和方法中的参数,可以理解为是一个数组结构。

操作数栈作为每条指令的工作区域,指令对数据的操作都要经过操作数栈的入栈出栈来实现。

剩余两个这里就不展开细说了。

上述知识均来自《深入理解Java虚拟机第3版》

有了上面的知识后,直接对编译后的class字节码文件进行javap -c反汇编得到下面的代码。为了方便理解,我对关键部分做了中文注释。如果要具体了解每个指令的用处,请自行搜索“JVM指令集”

Compiled from "Test.java"

public class test.Test {

public test.Test();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

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

Code:

0: iconst_0 //将0压入操作数栈顶部

1: istore_1 //弹出操作数栈顶元素,保存到局部变量表第1个位置

2: iconst_0 //将0压入操作数栈顶部

3: istore_2 //弹出操作数栈顶元素,保存到局部变量表第2个位置

4: iload_1 //将局部变量表第1个位置的值(也就是a的值)压入操作数栈顶部

5: bipush 10 //将10压入到操作数栈顶

7: if_icmpge 21 //比较操作数栈顶两int型数值大小,当结果等于0(相等)时跳转到21条指令执行,比较完成后清空栈顶两元素

10: iload_2 //将局部变量表第2个位置的值(也就是b的值)压入操作数栈顶部

11: iinc 2, 1 //将局部变量表第2个位置的值(也就是b的值)进行+1操作

14: istore_2 //弹出操作数栈顶元素,保存到局部变量表第2个位置(这是关键,这里的0将原先+1后的b给覆盖了,后面每次循环都被0覆盖了)

15: iinc 1, 1 //将局部变量表第1个位置的值(也就是a的值)进行+1操作

18: goto 4 //无条件跳转到第4条指令

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

24: iload_2

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

28: return

}

可以看到最关键的是第14条指令,每次循环都是先将b的值获取并存放到操作数栈,然后通过iinc指令直接将局部变量表中的b加1,再又将操作数栈中b原先的值0覆盖到局部变量表中的b,所以b最终还是0。

后面有时间再来做个动态图演示吧。

d8538a08e9b5cf5f5875d4fb19b50151.gif

本文地址:https://blog.csdn.net/c_o_d_e_/article/details/112283353

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值