Java 类文件结构
1、Class文件是一组以8位字节为基础单位的二进制流。文件格式统一采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。
2、无符号数属于基本的数据类型,以u1、u2、u4、u8来分别表示1/2/4/8个字节的无符号数。无符号数可以用来描述数字、索引引用、数量值、或者按照UTF-8编码构成字符串值。
3、表是由多个无符号数或者其他表作为数据项构成的符合数据类型,所有表都习惯性的以“_info”结尾。
4、无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式,这时称为某一类型的集合。
5、每个Class文件的头4个字节称为魔数,它的唯一作用是确定这个文件是否是一个能被虚拟机接受的Class文件。使用魔数而不是扩展名来进行身份识别主要是基于安全方面的考虑,因为文件扩展名能随意改动。Class文件的魔数值为:0xCAFEBABE。
6、紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6个字节是次版本号,第7和第8个字节是主版本号。Java的版本号是从45开始的,JDK1.0~1.1使用了45.0~45.3的版本号,JDK1.1之后的每个JDK大版本发布主版本号向上加1,高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件,即使文件格式并未发生任何变化,虚拟机也必须拒绝执行超过其版本号的Class文件。
7、紧接着版本号之后的是常量池入口,常量池是Class文件中的资源仓库,是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时还是Class文件中第一个出现的表类型数据项目。
8、常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值。这个容量计数是从1开始,而不是从0开始,比如常量池容量显示为22,代表常量池中有21项常量。0空出来有特殊用途:某些指向常量池的索引值的数据再特定情况下需要表达“不引用任何一个常量池项目”的含义,这种情况就可以把索引值置为0来表示。
9、常量池主要存放两大类常量:字面量和符号引用。
10、字面量比较接近Java语言层面的常量概念,如文本字符串、声明为final的常量值等。
11、符号引用属于编译原理方面的概念,包括三类常量:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。
12、紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息。
13、类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合。
Class文件由这三项数据来确定这个类的继承关系,类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于Java语言的单继承,所以父类索引只有一个,除了Object类之外,所有的Java类都有父类,也就是说除了Object类之外,其他所有的Java类的父类索引都不为0。接口索引集合用来描述这个类实现了哪些接口,这些被实现的接口将按implements语句(如果这个类本身是一个接口,则应当是extends语句)后的接口顺序从左到右排列在接口索引集合中。
14、字段表用于描述接口或类中声明的变量,字段包括类级变量和实例级变量,不包括方法内部声明的局部变量。
每一个 Class 文件对应于一个如下所示的 ClassFile 结构体。