不写废话,帮助你快速理解应对面试
目录
class类文件的作用
class类文件的结构
1. 数据结构
2. class文件结构
魔数
版本
常量池
访问标志
类/父类/接口
字段描述集合
方法描述集合
属性描述集合
class类文件的作用
Java能够实现"一次编译,到处运行”,这其中class文件要占大部分功劳。为了让Java语言具有良好的跨平台能力,Java独具匠心的提供了一种可以在所有平台上都能使用的一种中间代码——字节码类文件(.class文件),同时也解除了 Java 虚拟机和 Java 语言之间的耦合。
class类文件的结构
数据结构
Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符。Class文件中只有两种数据类型:无符号数和表。
无符号数:属于基本的数据类型,有u1, u2, u4, u8,分别代表1个字节、2个字节、4个字节和8个字节的无符号数。
表:表是由多个无符号数或者其他表作为数据项构成的复合数据类型,class文件中所有的表都以“_info”结尾。其实,整个 Class 文件本质上就是一张表。
class文件结构
在class文件中只存在无符号数和表这两种数据结构。这些结构按照预先规定好的顺序紧密的从前向后排列,相邻的项之间没有任何间隙。如下图所示:
当 JVM 加载某个 class 文件时,JVM 就是根据上图中的结构去解析 class 文件,加载 class 文件到内存中,并在内存中分配相应的空间。具体某一种结构需要占用大多空间,可以参考下图:
魔数
在class文件开头的四个字节是class文件的魔数,它是一个固定的值——0XCAFEBABE。
魔数是class文件的标志,也就是说它是判断一个文件是不是class格式文件的标准。
版本
紧跟在魔数后面的两个字节代表当前class文件的版本号。
前两个字节0000代表次版本号(minor_version),后两个字节0034是主版本号(major_version),对应的十进制值为 52,也就是说当前 class 文件的主版本号为 52,次版本号为 0。所以综合版本号是 52.0,也就是 jdk1.8.0
常量池
紧跟在版本号之后的是一个叫作常量池的表(cp_info)。
在常量池中保存了类的各种相关信息,比如类的名称、父类的名称、类中的方法名、参数名称、参数类型等,这些信息都是以各种表的形式保存在常量池中的。
常量池中的每一项常量都是一个表,不同的表是有不同的结构,下面是14种表的具体含义:
举个例子:
比如第3行的开头是07是,那么就是对应CONSTANT_Class_info这个info,而CONSTANT_Class_info对应的是下面的数据结构:
表解释说明:
tag:占用一个字节大小。比如值为7,说明是CONSTANT_Class_info类型表。
name_index:是一个索引值,可以将它理解为一个指针,指向常量池中索引为 name_index 的常量表。比如 name_index = 2,则它指向常量池中第 2 个常量。
紧跟07 后面的11就是索引第11项常量的意思,第11项是01 0003 69 6e 63, 其中tag是01,也就是CONSTANT_utf8_info这个info,它的数据结构:
所以,长度是3,往后数三个字节就是69 6e 63,对应的就是inc,这个也就是方法的名称。
访问标志
在常量池之后紧接这两个字节是访问标志,识别一些类或者接口层次的访问信息:
类/父类/接口
在访问标志后分别是this_class/super_class/interfaces_count
0003 //this_class 确定这个类的全限定名
0004 //super_class java.lang.Object该值就是0000
0000 //interfaces_count 该类没有实现任何接口,接口的索引表不占用任何字节
字段描述集合
对于 Java 类中的变量,也可以使用 public、private、final、static 等标识符进行标识。因此解析字段时,需要先判断它的访问标志,字段的访问标志如下所示:
方法描述集合
方法表集合和字段表集合很类似,有一个区别就是用描述符描述方法时,需要先参数列表后返回值,
并且有自己的访问标志,具体如下:
属性描述集合
属性表结构并没有一个固定的表结构,各种属性表只要满足以下结构就可以了: