第6章 java类文件结构
class 文件结构
- 主要是理解class文件编译成字节码以后的存储方法
- 本次讨论内容主要是class文件,不包括动态生成。
- class文件整体上可以划分为Code和元数据,两部分
概述:
- Class文件是以8位字节为基础单位的二进制流,jvm规范规定,class文件结构类似于c语言的伪结构体(包含两种数据结构)
- 无符号数:基本数据类型。U1,U2,U4,U8分别代表1个字节,2个字节,4个字节和8个字节。
- 描述数字,索引引用,数值量,或者按照UTF-8编码构成字符串值。
- 表:由无符号数或者其他表作为数据项,组成的符合数据结构。
- 描述有复合结构的数据。
- 整个Class文件就是一张表。
一、魔数
- class文件起始4个字节称为魔数
- 不使用文件后缀区分是否是class文件,主要是基于安全考虑
- tip:类加载过程中,一边加载一边进行验证,他们是同步进行的
- 魔数值:0XCAFEBABE
二、版本号
- 紧接着4个字节(5-8),(5-6)class文件次版本号,(7-8)文件主版本号
- jvm拒绝执行超过自己版本号的class文件
三、常量池入口
1、常量池:
- class文件的资源仓库
- class文件中最大的数据项目之一,也是和其他项目关联最多的数据类型
- 入口放置一个U2类型数据, 代表常量池计数容量(从1开始,在0时表示不引用常量池任何一个值)
2、常量池中存放两大类常量:
- 字面量
- 接近java的常量概念,文本字符串,生命final的常量值(JDK1.8以后把String移到了堆中)
- 符号引用
- 类和接口的全限定名(包名+类名)
- 字段的名称和描述符
- 方法的名称和描述符
- class文件中没有办法保存方法、字段的内存信息(Class只是一个文件)
- 运行期间,常量池中的链接才能对应内存中的地址
- 常量池中每一项都是一个表
四、访问标志
- 常量池结束后,接着2个字节表示访问标志(类修饰符,类相关信息)
- 类还是接口
- 是否是public
- 是否abstract
- 如果是类的话,是否是final等等
五、类索引集合
- 确定类的继承关系
- 类索引和父类索引,都是U2类型
- 类索引,确定这个类的全限定名
- 父类索引,确定该类的父类全限定名
- 除了Object外,所有类都有父类
- 接口是一组U2类型的索引数据集合
六、字段表集合
- 字段表描述接口或类中的变量(对象的成员变量)
- 包括class级变量和obj级别变量。但不包括方法内的变量
七、方法表集合
- 对方法的描述和对字段的描述完全一致
- 方法表结构:
- 访问标志(方法访问权限)
- 名称索引
- 描述符索引
- 属性表集合 (方法的实现)
八、属性表集合
- 概述:
- 描述某些场景专有信息
- class文件,字段表,方法表,都可以携带自己的方法表。
1、code属性
- 出现在方法表的属性集合中
- 接口和抽象类的抽象方法中就不存在code
- this:
- 实例方法的局部变量表中,至少存在一个指向当前实例的局部变量
- 局部变量表中也会预留出第一个slot位存放对象实例引用。
2、Exceptions属性
- 列举方法中可能抛出的受检查的异常(throws 异常)
3、LineNumberTable属性
4、LocalVariableTable属性
- 描述栈帧局部变量表中变量与java源码中定义变量的关系
5、contentValue属性
- 通知虚拟机为static属性赋值
- 为非static变量属性赋值(obj成员变量):
- 为static变量赋值(class变量)
- 被final和static共同修饰的基本数据类型和String用ContentValue保存
6、innerClass属性
7、Deprecated及Synthic属性
- Deprecated注解中的 @deprecated,表示该方法不推荐使用
- Synthic不是java产生的,而是编译器自行产生的
8、StackMapTable属性
- 复杂的变长属性,jvm加载字节码验证阶段被新类型验证器使用
9、Signature
- 可选定长属性,出现于类、属性表、方发表的属性表中。
- 主要是针对java使用伪泛型,反射困难,而增设
10、BootstrapMethod