类文件结构
JVM能理解的代码就叫做字节码,扩展名.class,不面向任何特定处理器,只面对虚拟机。
类文件结字节码结构
魔数+副版本号+主版本号+常量池计数器+常量池数据区+访问标志+类索引+父类索引+接口计数器+接口信息数据区+字段计数器+字段信息数据区+方法计数器+方法信息数据区+属性计数器+属性信息数据区
ClassFile {
u4 magic; //Class 文件的标志
u2 minor_version;//Class 的小版本号
u2 major_version;//Class 的大版本号
u2 constant_pool_count;//常量池的数量
cp_info constant_pool[constant_pool_count-1];//常量池
u2 access_flags;//Class 的访问标记
u2 this_class;//当前类
u2 super_class;//父类
u2 interfaces_count;//接口
u2 interfaces[interfaces_count];//一个类可以实现多个接口
u2 fields_count;//Class 文件的字段属性
field_info fields[fields_count];//一个类会可以有多个字段
u2 methods_count;//Class 文件的方法数量
method_info methods[methods_count];//一个类可以有个多个方法
u2 attributes_count;//此类的属性表中的属性数
attribute_info attributes[attributes_count];//属性表集合
}
魔数
每个Class文件的头四个字节为魔数,只为了确定这个文件是否能被虚拟机接收。
版本号
第五第六字节为副版本号,七八为主版本号,
高版本虚拟机可以执行低版本编译器产生的Class文件,反之不行
常量池
constant_pool 计数两字节,计数器从1开始,0代表不引用任何一个常量池。
常量池主要存放:字面量和符号引用。字面量如文本字符串,声明为final的常量。符号引用包括:
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
常量池中每个常量就是一个表,表的第一位表示常量类型,举例:
tag 类型
1 CONSTANT_utf8_info
3 CONSTANT_Integer_info
10 CONSTANT_Methodref_info
一直到18 CONSTANT_InvokeDynamic_info
访问标志
用于识别一些类或者接口层次的访问信息,包括:Class 类抽象或者公共,是否final
当前类索引,父类索引与结构索引集合
类索引用来确定类的全限定名,注意:java.lang.Object 父类索引为0,接口索引可以有多个
字段集合
field info 用于描述接口和类中声明的变量。
field_info{
u2 access_flags; //字段的作用域 public?static?transient?final?volatile?
u2 name_index;
u2 descriptor_index;
u2 attributes_count;//存放属性个数
attribute_info attributes[attributes_count]
}
方法表集合
与字段集合几乎完全一样的结构,访问标志,名称索引,描述索引,属性个数,具体属性。
注意:可视性volatile 和 序列化 transient 不可以修饰方法,所有也就没有这两个access_flags,但是会有synchronized 同步 native 本地 abstract 抽象,多了这几个访问标志。
属性表集合
Class文件中,字段表,方法表都可以有属性表集合,属性表自身限制宽松,只要不重复,都可以写,JVM会忽略自己不认识的属性。