JVM 字节码(字节码指令 和 操作数栈、常量池的关系)

字节码指令

构造方法 的字节码指令

2a b7 00 01 b1

那这些具体代表着什么含义?我们可以在官方文档当中进行查看不同的数值代替什么不同的含义:以2a为例,在这里都是十六进制的数,在文档当中查找0x2a,其余指令同理:官网文档:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html

在这里插入图片描述

  1. 2a => aload_0 加载 slot 0 的局部变量,即 this,做为下面的 invokespecial 构造方法调用的参数
  2. b7 => invokespecial 预备调用构造方法,哪个方法呢?
  3. 00 01 引用常量池中 #1 项,即【 Method java/lang/Object."<init>":()V 】 构造方法,V表示无返回值
  4. b1 表示返回

第二个就是主方法的字节码指令 public static void main(java.lang.String[]);

b2 00 02 12 03 b6 00 04 b1

和上方同理,在官网文档当中查找字节码信息

  1. b2 => getstatic 用来加载静态变量,哪个静态变量呢?
  2. 00 02 引用常量池中 #2 项,即【Field java/lang/System.out:Ljava/io/PrintStream;】
  3. 12 => ldc 加载参数,哪个参数呢?
  4. 03 引用常量池中 #3 项,即 【String hello world】
  5. b6 => invokevirtual 预备调用成员方法,哪个方法呢?
  6. 00 04 引用常量池中 #4 项,即【Method java/io/PrintStream.println:(Ljava/lang/String;)V】
  7. b1 表示返回

javap工具

对class文件进行反编译,使用命令javap -v class文件名

在这里插入图片描述
字节码指令 和 操作数栈、常量池的关系

使用一段简单的java代码进行测试

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

运行java代码得到class文件,使用javap指令对class文件进行反编译,在这里第三行的32768这个数只,在这里只有Short所含的数字大小才会跟随变量进行保存,其余大的数值都会保存在常量池当中。

在这里插入图片描述
随后会将常量池载入到运行时常量池

在这里插入图片描述
方法字节码载入方法区

在这里插入图片描述
main 线程开始运行,分配栈帧内存

在这里插入图片描述
到这里就运行main方法当中的指令,在对class反编译后,查看对应的code

在这里插入图片描述

1 :bipush 10
  • 将一个 byte 压入操作数栈(其长度会补齐 4 个字节)
  • sipush 将一个 short 压入操作数栈(其长度会补齐 4 个字节)
  • ldc 将一个 int 压入操作数栈
  • ldc2_w 将一个 long 压入操作数栈(分两次压入,因为 long 是 8 个字节)
  • 这里小的数字都是和字节码指令存在一起,超过 short 范围的数字存入了常量池

在这里插入图片描述

2: istore_1

将操作数栈顶数据弹出,存入局部变量表的 slot 1

在这里插入图片描述

3: ldc #3

从常量池加载 #3 数据到操作数栈
Short.MAX_VALUE 是 32767,所以 32768 = Short.MAX_VALUE + 1 实际是在编译期间计算好的

在这里插入图片描述

4 : istore_2

在这里插入图片描述

5:iload_1 和 iload_2

读取数据到操作栈上

在这里插入图片描述
在这里插入图片描述

6:iadd

执行相加算法

在这里插入图片描述

7:istore_3

在这里插入图片描述

8:getstatic #4

在常量池当中找到成员变量的引用。

在这里插入图片描述
读取之后放入操作栈当中。

在这里插入图片描述

9:iload3

读取第3个栈当中的数据

在这里插入图片描述

10:invokevirtual #5
  • 找到常量池 #5 项
  • 定位到方法区 java/io/PrintStream.println:(I)V 方法
  • 生成新的栈帧(分配 locals、stack等)
  • 传递参数,执行新栈帧中的字节码

在这里插入图片描述
执行完毕,弹出栈帧,清除 main 操作数栈内容

在这里插入图片描述
return :完成 main 方法调用,弹出 main 栈帧,程序结束。

案例分析 a- -

一个简单的代码段进行测试:使用字节码的技术对这段代码进行分析:

public class interview {
    public static void main(String[] args) {
        int a=10;
        int b = a++ + ++a + a--;
        System.out.print(a);
        System.out.print(b);
    }
}

还是一样,先使用javap对class文件进行反编译,其中:

  • iinc 指令是直接在局部变量 slot 上进行运算
  • a++ 是先执行 iload 还是 先执行 iinc
  • ++a 是先执行 iinc 还是 先执行 iload

在这里插入图片描述

  1. bipush 10 把10放进操作栈当中
  2. istore_1 把10弹出,放进第一个栈帧当中
  3. iload_1 把第一个栈帧的数据读取出来放入操作栈当中
  4. linc 进行自增
  5. linc load先自增再load a=12
    在这里插入图片描述
  6. 先load再自减
    在这里插入图片描述
  7. 最后弹出数据的结果 a=11 b=34

条件判断指令

如下表所示:

在这里插入图片描述

  • byte , short , char都会按int比较,因为操作数栈都是4字节
  • goto用来进行跳转到指定行号的字节码

使用一个简单的判断的java代码进行测试

public class if_demo {
    public static void main(String[] args) {
        int a = 0;
        if (a == 0) {
            a = 20;
        } else {
            a = 10;
        }
    }
}

之后还是使用javap对class文件进行反编译:

在这里插入图片描述
循环指令控制

使用一段简单的java循环代码进行测试,在这里while循环和do while同理。

public class while_demo {
    public static void main(String[] args) {
        int a = 0;
        while (a < 10) {
            a++;
        }
    }
}

使用javap对class进行反编译,查看code编码

在这里插入图片描述
案例分析(循环)

查看以下代码段:判断x最后的值

public class case_analysis {
    public static void main(String[] args) {
        int i = 0;
        int x = 0;
        while (i < 10) {
            x = x++;
            i++;
        }
        System.out.println(x);
    }
}

答案是0,在这里的x=x++;这条命令在字节码当中分为了两个阶段,先进行load在进行ilic,可以发现,在这里先把x的值加载到操作栈当中,而在栈帧当中进行自加,再把操作栈当中的x值覆盖栈帧当中的值,也就是一直是把x=0这个值对栈帧当中自增的值进行覆盖,所以x始终为0;

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Modify_QmQ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值