文章目录

  • 前言
  • 方法区
  • 常量池基本结构
  • JVM 所定义的11种常量
  • 常量池元素的复合结构
  • 常量池的结束位置
  • 常量池元素总数量
  • 第一个常量池元素
  • 父类常量
  • 变量型常量池元素

自己的学习笔记,部分节选自《揭秘java虚拟机》


前言

对于一个class文件,内容有:

以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数

这里主要说class文件中的常量池:
constant_pool_count
常量池计数器,constant_pool_count的值等于constant_pool表中的成员数加1。constant_pool 表的索引值只有在大于 0 且小于 constant_pool_count 时才会被认为是有效的 ,对于 long 和 double 类型有例外情况。

注意:虽然值为 0 的 constant_pool 索引是无效的,但其他用到常量池的数据结构可以使用索引 0 来表示“不引用任何一个常量池项”的意思。

constant_pool[ ]
常量池,constant_pool 是一种表结构,它包含 Class 文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量。常量池中的每一项都具备相同的格式特征——第一个字节作为类型标记用于识别该项是哪种类型的常量,称为“tagbyte”。常量池的索引范围是 1 至 constant_pool_count−1。

Jdk1.6及之前:有永久代, 常量池在方法区
Jdk1.7:有永久代,但已经逐步“去永久代”,常量池在堆
Jdk1.8及之后: 无永久代,常量池在元空间

常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串、被声明为final的常量值等。而符号引用则属于编译原理方面的概念,主要包括下面几类常量:

·被模块导出或者开放的包(Package)

·类和接口的全限定名(Fully Qualified Name)

·字段的名称和描述符(Descriptor)

·方法的名称和描述符

·方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)

·动态调用点和动态常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)

方法区

既然提到常量池就顺便提一下方法区,方法区主要保存的信息是类的元数据。方法区与堆空间类似,它也是被JVM中所有的线程共享的区域。方法区中最为重要的是类的类型信息、常量池、域信息、方法信息。类型信息包括类的完整名称、父类的完整名称、类型修饰符(public/protected/private)和类型的直接接口类表。

常量池基本结构

Java类所对应的常量池主要由常量池数量和常量池数组两部分组成(如下图所示),常量池数量紧跟在次版本号的后面,占2字节。常量池数组则紧跟在常量池数量之后。 常量池数组,顾名思义,就是一个类似数组的结构。这个数组固化在字节码文件中,由多个元素组成。与一般数组概念不同的是,常量池数组中不同的元素的类型、结构都是不同的,长度也是不同的,但是每一种元素的第一个数据都是一个u1类型,该字节是标志位,占1个字节(如图4.4所示)。JVM解析常量池时,根据这个u1类型来获取该元素的具体类型。常量池的结构组成如图所示。

使用结构化的方式来描述常量池数组的编排,可以如下描述: tag1元素内容1 tag2元素内容2 tag3元素内容3 … tagn元素内容n 这里为了描述,在tag与元素内容之间添加了空格,但实际的class 二进制文件中,这些tag与元素内容之间绝没有任何空格信息,也没有任何其他的多余信息,tag后面紧跟着元素内容,第一个元素内容结束了,紧接着就是第二个元素的tag信息,由此可见,整个字节码文件的格式设计都是非常紧凑的。

JVM 所定义的11种常量

常量池元素中的不同元素结构与类型都是不同的,正因如此,JVM只能定义有限的元素类型,并针对有限的类型进行专门解析。JVM一共定义了11种常量,
 JVM常量池元素一览表  

常量池元素的复合结构

常量池数组中的每一种元素的内容都是复合数据结构的,下面分别给出JVM所定义的常量池中每一种元素的具体结构。 该表中tag值为1的常量池元素CONSTANT_Utf8_info,其组成结构为3部分,分别是:tag、length和bytes,其中tag和length的长度分别是u1、u2,即分别占1字节和2字节。而bytes则是字符串的具体内容,其长度是length字节。在字节码文件中,该常量池元素最终所占的字节数是: 1 + 2 + length 其他类型的常量池元素的组成结构类似。
常量池元素结构:

可以看到,类的方法信息、接口和继承信息、属性信息都是定义在NamedAndType_Info中的。

常量池的结束位置

相信有不少读者读到这里,可能潜意识里会突然蹦出这么一个问题:整个字节码文件由多个部分构成,常量池数组只是其中一块,JVM在解析字节码文件时,一定需要分别读取各个部分的字节流,其中也包括常量池数组。但是常量池中有部分元素的值是bytes数组,其长度是随机变化的,那么JVM在解析时,是如何知道整个常量池的信息解析到什么位置结束呢?其实经过分析不难发现,首先,class文件给出了常量池的总数;其次,凡是碰到有bytes数组的常量池元素,class文件在常量池的每一个元素之前都会专门划分出2字节用于描述该常量池元素内容所占的字节长度,这样一来,常量池中每一个元素的长度是确定的,而常量池的总数也是确定的,JVM据此便可以从class文件中准确地计算出常量池结构体的末端位置(起始位置不用计算,是定死的,从第9字节开始,前面8字节分别是魔数和版本号)。

常量池元素总数量

前面8字节用于描述魔数和版本号,从第9字节开始的一大段字节流都用于描述常量池数组信息。其中,第9和第10字节用于描述常量池元素的总数量。

第9和第10字节所保存的常量池数组大小是0x33,换算成十进制是51,说明该字节码文件中一共包含51个常量池元素。JVM规定,不使用第0个元素,因此实际上一共有50个常量池元素(下文在解析源码时,会看到源码中的确是从第1个元素开始解析的,而不是从第0个)。

第一个常量池元素

常量池数量之后(即从第11字节开始),就是常量池数组。每一个常量池元素都以tag位标开始,tag位标都只占1字节长度。如图所示。

第11字节对应的值是7,对照上文所给的常量池11种元素的复合结构可知,tag位标为7代表的是CONSTANT_Class_info,即类或接口的符号引用,这种类型的元素的结构组成如下:
◎ tag位标 占1字节
◎ index 占2字节
既然tag位标已经占据了字节码文件的第11字节,则接下来的第12和13字节将合起来表示index。如上图所示,这两个字节对应的值为2。

从第11字节开始,到第13字节为止,一个常量池元素就被描述完成。紧接着开始描述第2个常量池元素

第一个常量池元素后面紧跟着的是第二个常量池元素。其第一字节是01,表示这是一个UTF8编码的字符串,其结构是:
◎ tag位,占1字节
◎ length,占2字节
◎ bytes,占length字节
如图所示,tag位后面的2字节的值是4,表示bytes占4字节,其值为0x54657374,其中每两字节正好代表一个字符,对应的字符串是Test。

*

父类常量

刚才的第1与第2两个常量用于描述Java类型信息,接下来的第3与第4两个常量则用于描述父类信息。由于Test.Java类并没有显式继承任何类,因此编译后处理成默认继承,即父类是Java.lang.Object。
父类常量的tag位也是07,其类名是java/lang/Object
下面分别给出第3和第4这两个常量在文件中的内容。

图4.9显示,字符串的length值为0x10,即16,于是其后面的16字节都是bytes。由此可以进一步验证,字符串常量的结构由tag、length和bytes组成,bytes的长度由length指定。

变量型常量池元素

常量池中前面4个元素主要用于描述Java类自身的名称和其父类名称,接下来的字节码流则开始描述类中的变量信息,这些变量既包括类的成员变量,也包括类变量(即静态变量)信息。 首先看类成员变量a的信息

图所选中的8字节,一共包含两个常量池元素信息,这两个常量池元素的类型都是字符串,因为其tag位都是1。第一个字符串常量的length是1,其值(即bytes)是0x61,正好对应UTF-8编码的字符a。第二个字符串常量的length也是1,其值是0x49,正好对应UTF-8编码的字符I。在JVM规范中,若变量的类型是I,则表示该变量的实际类型是int。这与上文对变量a的定义一致。 接着看类变量si的定义,

所选中的27字节,一共描述了两个常量池元素,这两个常量池元素的类型也都是字符串。第一个字符串的length为2,其值是0x7369,对应utf-8编码的字符串si。第二个字符串的length为0x13,即19,其值是0x4C 6A 61 76 61 2F 6C 61 6E 67 2F 49 6E 74 65 67 65 72 3E,这一串值是ASCII字符,每2个十六进制数对应一个ASCII字符,这些数字连起来就对应一个字符串,所对应的字符串是Ljava/lang/Integer;。 这两个常量池元素合起来,描述了Test类中的static Integer si这样的类变量。

class字节码文件中的常量池结构详解相关推荐

  1. 【Java 虚拟机原理】Class 字节码二进制文件分析 二 ( 常量池位置 | 常量池结构 | tag | info[] | 完整分析字节码文件中的常量池二进制数据 )

    文章目录 前言 一.常量池结构分析 1.常量池位置 2.常量池结构 3.常量池单个常量 4.常量池单个常量 tag 标签 二.常量池字节码文件分析 0.常量池附加信息 1.常量池 #1 常量分析 2. ...

  2. 【Groovy】闭包 Closure ( 闭包定义 | 闭包类型 | 查看编译后的字节码文件中的闭包类型变量 )

    文章目录 一.闭包定义 二.闭包类型 三.查看编译后的字节码文件中的闭包类型变量 一.闭包定义 闭包 Closure 是 Groovy 中最常用的特性 , 使用闭包作为参数是 Groovy 语言的明显 ...

  3. YOLOv5中的SPP/SPPF结构详解

    深度学习入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删. 目录 一.SPP的应用的背景 二.SPP结构分析 三.SPPF结构分析 四.YOLOv ...

  4. java中计算一个文件的总字节数_【JVM故事】一个Java字节码文件的诞生记

    作者:李新杰·转自微:信公众号"编程新说" 万字长文,完全虚构.(12000字) (一) 组里来了个实习生,李大胖面完之后,觉得水平一般,但还是留了下来,为什么呢?各自猜去吧. 李 ...

  5. 【Java 虚拟机原理】栈帧 | 动态链接 | 方法区 | 字节码文件二进制分析

    文章目录 前言 一.方法区 二.字节码二进制文件分析 三.动态链接 1.动态链接简介 2.静态链接与动态链接 3.早期绑定 和 晚期绑定 4.动态链接示例 前言 " 栈帧 " 中存 ...

  6. 字节码文件的内部结构之谜

    如果计算机的 CPU 只有「x86」这一种,或者操作系统只有 Windows 这一类,那么或许 Java 就不会诞生.Java 诞生之初就曾宣扬过它的初衷,「一次编写,多处运行」,而它之所以能够实现跨 ...

  7. 字节码文件及字节码指令

    我记得开始学习Java的第一堂课时,我的大学老师是这样说的,Java号称是"一次编写,到处运行",为什么有底气这样说,是因为Java程序并不是直接运行在操作系统上的,它通过不同操作 ...

  8. JVM 字节码文件与类加载

    文章目录 前端编译器与后端编译器 解释执行和 JIT&AOT "类"的生命周期 字节码文件的读取解析 "类"的生命周期 加载阶段 链接阶段 初始化阶段 ...

  9. 【Android 逆向】类加载器 ClassLoader ( 使用 DexClassLoader 动态加载字节码文件 | 拷贝 DEX 文件到内置存储 | 加载并执行 DEX 字节码文件 )

    文章目录 一.拷贝 Assets 目录下的 classes.dex 字节码文件到内置存储区 二.加载 DEX 文件并执行其中的方法 三.MainActivity 及执行结果 四.博客资源 一.拷贝 A ...

最新文章

  1. FastJson之有道翻译
  2. 微软 Excel 365 里如何设置下拉菜单和自动高亮成指定颜色
  3. 计算机组成原理第二版复习大纲,计算机组成原理复习大纲
  4. mysqld install mysql default_MySQL安装默认配置
  5. sae mysql 同步本地_MYSQL入门之三_将本地MySQL数据导入SAE数据库_MySQL
  6. oracle 编程必读_现在学习的编程语言,网络监视工具,备份解决方案以及更多必读内容
  7. python3 绝对值_Python的绝对值最大的数字,python
  8. 数据挖掘与其商务智能上的应用的实验报告
  9. 利用SQL语言实现数据库的静态完整性
  10. ganglia不能获取gpu_免费试用亚马逊云服务器进行深度学习实验:免环境配置/GPU支持...
  11. ros重置后地址_RouterOS中BGP软重新配置 - ROS软路由论坛 - ROS教程 - RouterOS - ROS之家 - ROS脚本生成器 - Powered by Discuz!...
  12. 我国5G现状:今年底或发放5G牌照
  13. 设备信息管理系统(C语言)
  14. 传输层协议《TCP/IP详解 卷1:协议》学习笔记
  15. Mint-Ui安装及使用办法
  16. 学习软件技术的五大技巧
  17. Java基础篇--概念理解(重写、接口)
  18. mac笔记本怎么外接显示屏_苹果MAC笔记本怎么外接显示器
  19. 骏文c语言银行系统,C语言学生选课管理系统
  20. 双十一苏宁“狮晚”PK天猫“猫晚”,玩的是娱乐,赢的是流量

热门文章

  1. canoco5主成分分析步骤_基于R语言的主成分分析
  2. s3c2440芯片累加汇编语言,s3c2440 --跑马灯 C+汇编代码
  3. 设计一款博弈类游戏的人机对战算法、策略_卡牌游戏八合一,华人团队开源强化学习研究平台RLCard...
  4. 火影忍者手游服务器维护4月4,火影忍者手游4月14日联服公告-火影忍者手游4月14日联服时间_牛游戏网...
  5. 甘肃省计算机等级考试在线支付,甘肃计算机等级考试入口
  6. android 将SQLite数据库的表格导出为csv格式,并解析csv文件
  7. 八十九、常见的圣杯布局和双飞翼布局
  8. 七十九、TodoList示例 深入Redux的工作流
  9. 六十七、Leetcode数组系列(下篇)
  10. CIKM 2021 | Deep Retrieval:字节跳动深度召回模型论文精读