暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

字节码解析 之 常量池(Constant Pool)

皮皮克克 2022-11-05
16

点击关注公众号,干货第一时间送达



最近双十一。。。

是的,又到了剁手的时候。

看看所剩无几的余额,只想对当初创造出“双十一”的阿里大佬张勇说,

我谢谢你

话不多说,咱们剩饭继续热着吃。

上篇文章:字节码解析 之 魔数+版本号 主要介绍了字节码文件里面的前两个部分,魔数(Magic Number)版本号 (Version)。

今天,小编来讲解一下跟在版本号后面的另一个部分,常量池(Constant Pool)



一,常量池(Constant Pool)概述

常量池包含了 class 文件结构及其子结构中所引用的所有字符串常量、类或接口名、字段名和其他常量


演示代码:

public class BytecodeTest {

    private int num;
    public int add(){
        num = num + 2;
        return num;
    }
}


这里,我们可以借助 jclasslib 工具进行字节码文件查看。

(关于 jclasslib 插件工具的使用,小编在前面的文章:栈帧的内部结构 之 局部变量表 里面有介绍到,感谢的小伙伴可以点击翻看)


这就是常量池(Constant Pool)



二,常量池中的字面量(Literal)和符合引用(Symbolic Reference)

常量池主要存放两大类常量,字面量(Literal)符号引用(Symbolic References)
它包含了 class 文件结构及其子结构中所引用的所有字符串常量、类或接口名、字段名和其他常量.


具体的 字面量符合引用 包括的数据如下:

常量具体的常量
字面量文本字符串

声明为 final 的常量值
符合引用类和接口的全限定名

字段的名称和描述符

方法的名称和描述符


1,字面量例子

String str = "pipickeke";
final int age = 18;


2,符合引用的内容概述

(1)全限定名

com/pipickeke/boot/test/BytecodeTest

这种就是 类的全限定名。


(2)简单名称

简单名称指 没有类型和参数修饰符的方法或者字段名称。例如演示代码中的  add() 方法 和 num 字段:

public class BytecodeTest {

    private int num;
    public int add(){
        num = num + 2;
        return num;
    }
}


简单名称分别是  add 和 num。


(3)描述符

描述符的作用是 用来描述字段的数据类型、方法的参数列表(包括数量、类型和顺序)和返回值。

根据描述符规则,基本数据类型(byte、char、double、float、int、long、short、boolean)以及代表无返回值的 void 类型都用一个大写字符表示,而对象类型则用字符L加对象的全限定名表示。具体如下:

标志符含义
B基本数据类型byte
C基本数据类型char
D基本数据类型double
F基本数据类型float
I基本数据类型int
J基本数据类型long
S基本数据类型short
Z基本数据类型boolean
Vvoid类型
L对象类型,例如 Ljava/lang/Object;
[数组类型,代表一维数组。例如 double[][],对应为 [[D


看不懂?没关系,来段代码:


懂了吧!

咱们继续。



三,字节码解析 常量池

1,演示代码不变,还是:

public class BytecodeTest {

    private int num;
    public int add(){
        num = num + 2;
        return num;
    }
}


2,通过 Binary Viewer 查看该源代码,经过编译,生成的字节码文件如下:

(关于 Binary Viewer 软件的使用,小编在之前的文章:字节码解析 之 魔数+版本号 有介绍到,感兴趣的小伙伴可以点击翻看)


一看就懵了吧?

小编第一次看也是完全懵了啊!

不要紧,咱们一点点解析。


3,常量类型和结构参照表

根据Oracle官方提供的数据,制作如下常量池参照表:

(总共有很多种,这里小编只列举了本文演示代码会涉及到的常量)


4,开始解析字节码文件

(1)我们首先把在上面步骤2中,查看得到的字节码文件导入到 Excel

就是下图的数据:


导入到 Excel,如下:


(2)开始解析

1> 魔数(u4:4个字节)、副版本(u2:2个字节)、主版本(u2:2个字节)


可以对照上篇文章字节码解析 之 魔数+版本号中的第二步骤的数据表:


2> 常量池计数器(u2:2个字节)

3> 常量池表,表中具体的内容,由前面的 常量池计数器决定,当前有 21 个常量,分别如下:

第1个常量项:(CONSTANT_Methodref_info):

 tag 为 0x0A,对应十进制值是 10,参考上面步骤的 常量类型和结构参照表:


第2个常量项:(CONSTANT_Fieldref_info):

 tag 为 0x09,对应十进制值是 9,参考上面步骤的 常量类型和结构参照表:

第3个常量项:(CONSTANT_Class_info):

 tag 为 0x07,对应十进制值是 7,参考上面步骤的 常量类型和结构参照表:


第4个常量项:(CONSTANT_Class_info):

 tag 为 0x07,对应十进制值是 7,参考上面步骤的 常量类型和结构参照表:


第5个常量项:(CONSTANT_utf-8_info):

 tag 为 0x01,对应十进制值是 1,参考上面步骤的 常量类型和结构参照表:

图片中,length值为 0x0003,表示该处的字符串长度为 3 ,则后面跟着的 3个字节码值,都属于该常量项,即 0x6E、0x75、0x6D 属于该常量项。


第6 - 17个常量项:(CONSTANT_utf-8_info):

(截图的时候小编数漏了一个,以文字为准)


第18-19个常量项:(CONSTANT_NameAndType_info):

 tag 为 0x0C,对应十进制值是 12,参考上面步骤的 常量类型和结构参照表:


第20-21个常量项:(CONSTANT_utf-8_info):


至此,就是常量池表中全部的 21 个常量项。

我们可以通过 jclasslib 查看字节码文件进行比对:

(关于 jclasslib 插件工具的使用,小编在前面的文章:栈帧的内部结构 之 局部变量表 里面有介绍到,感谢的小伙伴可以点击翻看)

这21个常量项,只对应小编的演示代码,生成的字节码文件。


所以你懂得!

今天的内容就这样。


结束语:
Ok,到此为止,就是本篇文章的全部内容了。
该文章主要讲了字节码文件的 常量池(Constant Pool),为了更好的理解本文,可以翻看上篇文章:
字节码解析 之 魔数+版本号
如果各位有不懂的地方,欢迎发消息给小编,小编会进行详细地解答。
最后,请屏幕前的各位小可爱,动动你们的小手,给小编一个“在看”吧!

文章转载自皮皮克克,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论