JVM类文件结构

类文件结构

无关性的基石

各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码 (ByteCode)是构成平台无关性的基石.实现语言无关性的基础仍然是虚拟机和字节码存储格式.

Class类文件的结构

​ Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑 地排列在Class文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容 几乎全部是程序运行的必要数据,没有空隙存在。当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前[1]的方式分割成若干个8位字节进行存储。

​ 根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构来 存储数据,这种伪结构中只有两种数据类型:无符号数和表,后面的解析都要以这两种数 据类型为基础,所以这里要先介绍这两个概念。

​ 无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4 个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8编码构成字符串值。 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地 以"_info"结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一 张表,如下图.

类型名称数量
u4magic1
u2minor_version1
u2major_version1
u2constant_pool_count1
cp_infoconstant_poolconstant_pool_count-1
u2access_flags1
u2this_class1
u2super_class1
u2interfaces_count1
u2interfacesinterfaces_count
u2fields_count1
field_infofieldsfields_count
u2methods_count1
method_infomethodsmethods_count
u2attributes_count1
attribute_infoattributesattributes_count
魔数和class文件的版本

​ 每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是确定这个文 件是否为一个能被虚拟机接受的Class文件.

​ 紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6个字节是次版本号 (Minor Version),第7和第8个字节是主版本号(Major Version)。

常量池

​ 紧接着主次版本号之后的是常量池入口.入口u2类型的数据代表常量池的数量,从1开始.第0位用来表达特殊含义.

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

  • 类和接口的全限定名(Fully Qualified Name)
  • 字段的名称和描述符(Descriptor)
  • 方法的名称和描述符

常量池的项目类型如下图:

在这里插入图片描述

访问标志

​ 在常量池结束之后,紧接着的两个字节代表访问标志(access_flags),这个标志用于 识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public 类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。具体的标志位以及含义见下表:

标志名称标志值含义
ACC_PUBLIC0x0001是否为public
ACC_FINAL0x0010是否为final,只有类可设置
ACC_SUPER0x0020JDK 1.0.2之后编译出来的类的这个标志为真
ACC_INTERFACE0x0200标识是接口
ACC_ABSTRACT0x0400是否为abstract,接口和抽象类为真
ACC_SYNTHETIC0x1000标识这个类并非由用户代码产生
ACC_ANNOTATION0x2000标识这是一个注解
ACC_ENUM0x4000标识这是一个枚举
类索引、父类索引与接口索引集合

​ 类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引 集合(interfaces)是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类 的继承关系.

​ 类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限 定名。

​ 类索引、父类索引和接口索引集合都按顺序排列在访问标志之后,类索引和父类索引 用两个u2类型的索引值表示,它们各自指向一个类型为CONSTANT_Class_info的类描述 符常量,通过CONSTANT_Class_info类型的常量中的索引值可以找到定义在 CONSTANT_Utf8_info类型的常量中的全限定名字符串.

字段表集合

class文件格式第11行,u2类型的fields_count一个.

字段表不像常量项那样各有各的结构,字段表的结构是统一的,如下表

类型名称数量
u2access_flags1
u2name_index1
u2descriptor_index1
u2attributes_count1
attribute_infoattributesattributes_count
访问标识符

access_flags可以表明字段所具有的特性,access_flags由下表

标志名称标志值含义
ACC_PUBLIC0x0001是否为public
ACC_PRIVATE0x0002是否为private
ACC_PROTECTED0x0004是否为protected
ACC_STATIC0x0008是否为static
ACC_FINAL0x0010是否为final
ACC_VOLATILE0x0040是否为volatile
ACC_TRANSIENT0x0080是否为transient
ACC_SYNTHETIC0x1000是否由编译器自动生成
ACC_ENUM0x4000是否为enum
简单名和描述符

name_index和descriptor_index两者都为常量池的索引。

name_index为字段的简单名索引(即不带有包名的名称)。

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

基本数据类型和表示无返回值的void的描述符都用一个大写字母来表示,对象类型则用L加对象的全限定名表示,如下表

描述符含义
Bbyte
Cchar
Ddouble
Ffloat
Iint
Jlong
Sshort
Zboolean
Vvoid
L对象类型
方法表集合

class文件格式第13行,u2类型的methods_count一个。

方法表结构与字段表结构一致,如下表

类型名称数量
u2access_flags1
u2name_index1
u2descriptor_index1
u2attributes_count1
attribute_infoattributesattributes_count

方法访问标志与字段访问标志略有不同

标志名称标志值含义
ACC_PUBLIC0x0001是否为public
ACC_PRIVATE0x0002是否为private
ACC_PROTECTED0x0004是否为protected
ACC_STATIC0x0008是否为static
ACC_FINAL0x0010是否为final
ACC_SYNCHRONIZED0x0020是否为synchronized
ACC_BRIDGE0x0040是否为编译器产生的桥接方法
ACC_VARARGS0x0080是否接受不定参数
ACC_NATIVE0x0100是否为native
ACC_ABSTRACT0x0400是否为abstract
ACC_STRICTFP0x0800是否为strictfp
ACC_SYNTHETIC0x1000是否由编译器自动生成

如果父类方法没有被重写,方发表中不会出现来自父类的方法,也有可能出现编译器自动添加的方法,如类构造器<clinit>和实列构造器<init>方法。

开始分析方法表集合:

0x0176+10~0x0176+11:00 01

该方法是public。

0x0176+12~0x0176+13:00 07

简单名索引为7,即<init>

0x0176+14~0x0176+5:00 08

描述符索引为8,即V()

0x0192+0~0x0192+1:00 01

属性个数为1。

接下来就是一个属性表。

属性表

在class文件、字段表和方法表都可以携带属性表集合,用于描述某些场景专有的信息。属性表开头都是u2类型的属性名称索引和u4类型的属性长度,紧接着就是不同属性的结构了。属性表中可能包含其他属性表。

Code属性表

类型名称数量
u2attribute_name_index1
u4attribute_length1
u2max_stack1
u2max_locals1
u4code_length1
u1codecode_length
u2exception_table_length1
exception_infoexception_tableexception_table_length
u2attributes_count1
attribute_infoattributesattributes_count
class文件属性表

在class文件、字段表和方法表都可以携带属性表集合,用于描述某些场景专有的信息。属性表开头都是u2类型的属性名称索引和u4类型的属性长度,紧接着就是不同属性的结构了。属性表中可能包含其他属性表。

分析方法类似,结果如下:

类型名称说明
u2attribute_name_index0x00 0DSourceFile
u4attribute_length0x00 00 00 02属性长度2字节
u2sourcefile_index0x00 0ESimple.java
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值