写点什么

JVM 实践 -- 实例解析字节码常量池

用户头像
林昱榕
关注
发布于: 1 小时前

目标

本文通过一个具体案例将 class 文件常量池数据结构和二进制文件存储格式对应起来分析,帮助加深对字节码常量池的理解。


字节码存储格式

为了能看懂二进制文件,需了解 class 字节码的存储格式,如下图所示:

注:u4 代表无符号 4 字节。

具体说明如下:


本文只分析常量池部分。常量池的结构如下:

常量池是一个变长结构,它的第一部分是 2 字节表示的池大小;第二部分是常量池项集合(索引号从 1 开始,0 属于保留索引,供特殊情况使用。最多包涵 n-1 个元素,因为 long 和 double 类型的常量会占用 2 个索引位置)。


每个常量池项的结构用伪代码表示如下:

第一个字节表示类型(tag),然后接下来的几个字节表示具体的内容。

常量池类型总共有 14 种,如下图:


案例分析

下面开始分析实例,代码如下:

public class Hello {  private int a = 1;  private long b = 2L;  public static void main(String[] args) {    System.out.println("Hello, World");   }}
复制代码


1)使用 javac 编译源文件:

javac Hello.java

2)使用 javap 工具查看.class:

javap -v Hello



可以看到常量池中总共有 38 个常量项(池大小=38+1=39)。同时 Long 占了 #13-#14 两个索引值。


3)使用 vi 查看.class 文件:

vi -b Hello.class

输入::%!xxd

十六进制表示结果如图:


4)将二进制里面的各个常量项逐个找出来,根据索引跟 javap 的输出结果做对应


下面是前面 7 个常量项的对应示意图,通过不同的颜色做区分:


分析如下:


1、前面 8 字节为魔数和版本号,第 9~10 字节为常量池大小为:0027,即:39。


2、索引 #1 的常量项类型为 0a,查表可知为 MethodRef 类型,该类型结构如下:

CONSTANT_Fieldref_info {
u1 tag; // 固定为10
u2 class_index; // 指向CONSTANT_Class_info的常量池索引值,表示方法所在的类信息
u2 name_and_type_index; // 指向CONSTANT_NameAndType_info的常量池索引值,表示方法的方法名、参数和返回值类型
}
复制代码

从图中可知,其 class_index 为 0002(#2),name_and_type_index 为 0003(#3)。


3、索引 #2 的常量项类型为 07,查表为 Class 类型,该类型结构如下:

CONSTANT_Class_info {
u1 tag; // 值固定为7
u2 name_index; // 常量池索引,指向CONSTANT_Utf8_info常量,这个字符串存储的是类或接口的全限定名
}
复制代码

其 name_index 为 0004(#4)


4、索引 #3 的常量项类型为 0c,查表为 NameAndType 类型,该类型结构如下:

CONSTANT_NameAndType_info{
u1 tag; // 固定为12
u2 name_index; // 指向常量池中的CONSTANT_Utf8_info的索引,字段或方法的名字
u2 descriptor_index; // 指向常量池中的CONSTANT_Utf8_info的索引,字段或方法的描述符
}
复制代码

其 name_index 为 0005(#5),descriptor_index 为 0006(#6)。


5、索引 #4#6 常量项类型都为 01,查表为 Utf8 类型,该类型结构如下:

CONSTANT_Utf8_info {
u1 tag; // 固定值1
u2 length; // 表示第三部分byte数组的长度
u1 bytes[length]; // 采用MUTF-8编码的长度为length的字节数组 }
复制代码

对应图中的黄、红、绿三条横线。


6、索引 #7 常量项类型为 09,查表为 Fieldref 类型,该类型结构如下:

ONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
复制代码

其 class_index 为 0008(#8),name_and_type_index 为 0009(#9)。


剩下的常量项按上述分析方法可逐一找出,不再赘述。


参考资料:

1、《深入理解 JVM 字节码》-张亚


也欢迎关注我的公众号(搜索:Make IT Simple),一起学习交流。


 欢迎关注“Make IT Simple”,一起搞定底层原理

发布于: 1 小时前阅读数: 5
用户头像

林昱榕

关注

开心生活,努力工作。 2018.02.13 加入

还未添加个人简介

评论

发布
暂无评论
JVM实践--实例解析字节码常量池