Java虚拟机学习(三)-类文件结构的简单介绍

我们都知道计算机在执行程序时,只能识别0和1格式的程序,但在Java虚拟机出现之后,便有了一种新的程序存储格式——字节码。也正因为实现了从机器码到字节码的转变,使得Java程序可以”Write Once, Run Anywhere”(一次编写,到处运行)。时至今日,出现了一大批基于虚拟机运行的语言,比如:Scala、Groovy等。
今天的学习结果就是记录一下Java程序在编译成字节码后的文件结构,也就是Class的文件结构。如果大家想要了解更多的相关介绍,可以阅读Java虚拟机规范。

1.Class类文件的结构
每个Class文件都是由8字节为单位的字节流组成。所有的16位、32位和64位数据都被构造成2个、4个和8个字节单位来表示。多字节数据项按照Big-Endian(以最高位字节放在地址最低位,最低位字节放在地址最高位的顺序存储)。

在Java虚拟机规范中使用类似于C语言结构体的伪结构来存储数据,这种伪结构有两种数据类型:无符号数和表。
无符号数属于基本数据类型,以u1、u2、u4、u8来分别表示1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值。
是由多个无符号数或者其他表作为数据项构成的复合数据类型。

Class类文件结构体

ClassFile {    
    u4 magic;   //魔数 有固定值0xCAFEBABE
    u2 minor_version;     //副版本
    u2 major_version;     //主版本
    u2 constant_pool_count;  //常量池计数器
    cp_info constant_pool[constant_pool_count-1];   //常量池
    u2 access_flags;   //访问标志
    u2 this_class;    //类索引,标识当前类  
    u2 super_class;   //父类索引,标识父类
    u2 interfaces_count;   //接口技术器
    u2 interfaces[interfaces_count];    //接口表  
    u2 fields_count;   //字段计数器
    field_info fields[fields_count];    //字段表
    u2 methods_count;   //方法计数器  
    method_info methods[methods_count];   //方法表
    u2 attributes_count;   //属性计数器  
    attribute_info   //属性表
} 

下面介绍一下结构体中各项的具体表述意义:
magic:魔数,魔数的唯一作用是确定这个文件是否为一个能被虚拟机所接受的 Class 文件。魔数值固定为 0xCAFEBABE,不会改变。

minor_version major_version :副版本号和主版本号,minor_version 和 major_version 的值分别表示 Class 文件的副、主版本。它们共同构成了 Class 文件的格式版本号。

constant_pool_count :常量池计数器,constant_pool_count的值等于constant_pool表中的成员数加1。constant_pool 表的索引值只有在大于 0 且小于 constant_pool_count 时才会被认为是有效的。

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

access_flags
访问标志,access_flags 是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性,如:public、abstract等。

this_class :类索引,this_class 的值必须是对 constant_pool 表中项目的一个有效索引值。constant_pool 表在这个索引处的项必须为 CONSTANT_Class_info 类型常量,表示这个 Class 文件所定义的类或接口。

super_class: 父类索引,对于类来说,super_class 的值必须为 0 或者是对 constant_pool 表中项目的一个有效索引值。如果它的值不为 0,那 constant_pool 表在这个索引处的项必须为 CONSTANT_Class_info 类型常量,表示这个 Class 文件所定义的类的直接父类。

扫描二维码关注公众号,回复: 2167230 查看本文章

interfaces_count :接口计数器,interfaces_count 的值表示当前类或接口的直接父接口数量。
interfaces:接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool 表中项目的一个有效索引值,它的长度为 interfaces_count。每个成员 interfaces[i] 必须为 CONSTANT_Class_info 类型常量,其中 0 ≤ i < interfaces_count。在 interfaces[]数组中,成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样,即 interfaces[0]对应的是源代码中最左边的接口。

fields_count :字段计数器,fields_count 的值表示当前 Class 文件 fields数组的成员个数。fields数组中每一项都是一个 field_info 结构的数据项,它用于表示该类或接口声明的类字段或者实例字段。
fields:字段表,fields数组中的每个成员都必须是一个 fields_info 结构的数据项,用于表示当前类或接口中某个字段的完整描述。fields数组描述当前类或接口
声明的所有字段,但不包括从父类或父接口继承的部分。

methods_count :方法计数器,methods_count 的值表示当前 Class 文件methods数组的成员个数。
methods:方法表,methods[]数组中的每个成员都必须是一个 method_info 结构的数据项,用于表示当前类或接口中某个方法的完整描述。

attributes_count :属性计数器,attributes_count 的值表示当前 Class 文件 attributes 表的成员个数。
attributes:属性表,attributes 表的每个项的值必须是 attribute_info 结构。在Java虚拟机规范里,Class 文件结构中的 attributes 表的项包括下列定义的属性:
InnerClasses、EnclosingMethod、Synthetic 、Signature 、SourceFile, SourceDebugExtension、Deprecated、RuntimeVisibleAnnotations、RuntimeInvisibleAnnotations以及BootstrapMethods属性。对于支持 Class 文件格式版本号为 49.0 或更高的 Java 虚拟机实现,必须正确识别并读取 attributes 表中的 Signature、RuntimeVisibleAnnotations和RuntimeInvisibleAnnotations。对于支持 Class 文件格式版本号为 51.0 或更高的 Java 虚拟机实现,必须正确识别并读取 attributes 表中的BootstrapMethods属性。

上述所有数据项的介绍都来自与Java虚拟机规范,更具体的描述可以参考Java虚拟机规范。

猜你喜欢

转载自blog.csdn.net/programerxiaoer/article/details/79180810
今日推荐