Java 类文件结构

Class类文件时一组以字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件中,没有任何分隔符。对于大于8位的数据均采用大头方式储存,文件中只有无符号数和表两种结构

无符号数有u1,u2,u4,u8,即1,2,4,8位字节,可以用来描述数字,索引引用,数量值或按照utf8编码的字符串值

表是由一组无符号数组成的结构,所有表均以_info结尾,整个Class文件本质上就是一张表,其按照以下数据项依次排列:

magic-->minor_version-->major_version-->constant_pool_count-->constant_pool-->access_flags-->this_class

-->super_class-->interfaces_count-->interfaces-->fields_count-->fields-->methods_count-->methods-->attributes_count-->attributes

1.magic u4

 魔数,Class文件以0xCAFEBABE开头

2.minor_version u2  major_version u2

次版本号和主版本号   jdk1.8的主版本号位52

3.constant_pool_count u2  constant_pool 

常量池,constant_pool_count代表常量池计数器,从1开始计数,所以常量池中常量个数等于constant_pool_count - 1,用0来表示“不引用任何常量池项目”

常量池主要存放字面量(Literal)和符号引用

字面量:字符串,被声明为final的值等

符号引用:包含以下三类常量

1)类和接口的全限定名

2)字段的名称和描述符

3)方法的名称和描述符

常量池中每一项都是一个表,一共有11中结构不同的数据表,以下是每个表所对应的标志(tag,类型为u1)

标志 类型(CONSTANT_xxx_info) 描述 结构(第一个字节均为对应的tag)
1 Utf8   UTF-8编码的字符串 length(u2) + bytes(length)
3 Integer  整型字面量 bytes(ur)
4 Float   浮点型字面量 bytes(u4)
5 Long   长整型字面量 bytes(u8)
6 Double   双精度浮点型字面量 bytes(u8)
7 Class   类或接口的符号引用 index(u2)
8 String   字符串类型字面量 index(u2)
9 Fieldref   字段的符号引用 index(u2) + index(u2)
10 Methodref 类中方法的符号引用 index(u2) + index(u2)
11 InterfaceMethodref 接口中的符号引用 index(u2) + index(u2)
12 NameAndType 字段或方法的部分符号引用 index(u2) + index(u2)

4.access_flags u2

访问标志,识别类或接口的访问信息,目前有以下8个标志:

标志名称 标志值 含义
ACC_PUBLIC 0X0001 是否是public
ACC_FINAL 0X0010 是否是final,只有类才可能有
ACC_SUPER 0X0020 jdk1.2之后都有
ACC_INTERFACE 0X0200 标志这是一个接口
ACC_ABSTRACT 0X0400 对于接口或抽象类为真,其他类为假
ACC_SYNTHETIC 0X1000 标志该类并非由用户代码产生
ACC_ANNOTATION 0X2000 标识这是一个注解
ACC_ENUM 0X4000 标识这是一个枚举

access_flag的值等于标志为真的标志值相与,例如0x0001|0x0010 = 0x0011 表示是public final的

5.this_class  u2  super_class  u2

类索引和父类索引,因为一个类只有一个父类,所以均用u2表示(与interface相对比),依据该值可以在常量池找到一个全限定名字符串

6.interfaces_count u2  interfaces

接口索引,以u2类型开头表示该类有interfaces_count个接口,然后依次是interfaces_count个u2类型值,依据该值可以在常量池找到一个全限定名字符串

7.fields_count u2  fields

字段表,用于描述接口或者类中声明的变量,包括以下几个项目:

1)access_flags:

字段修饰符,各种表示对应的标志值

标志名称 标志值
ACC_PUBLIC 0X0001
ACC_PRIVATE 0X0002
ACC_PRITECTED 0X0004
ACC_STATIC 0X0008
ACC_FINAL 0X0010
ACC_VOLATILE 0X0400
ACC_TRANSIENT 0X0800
ACC_SYNTHETIC 0X1000
ACC_ENUM 0X4000

2)name_index  descriptor_index

字段的简单名称及字段和方法的描述符

几个名词解释:

全限定符——如com/xiao/helloworld/Test

简单名称——定义变量i,i为简单名称

字段和方法的描述符——描述字段的数据类型,方法的参数列表(包括数量,类型及顺序),返回值

数据类型对应规则为:基本类型以及void用一个大写字母来表示(类型的第一个字母大写,除了long为J,boolean为Z);对于对象类型,使用字母L加上对象的全限定类名表示;对于数组,每一维度使用一个前置的[

描述方法时:按照先参数列表后返回值描述,参数列表严格按顺序放置在()中,如(IIFZ)V表示void xxx(int x,int x,float x,boolean x)

3)attributes_count  attributes

可能有的属性,例如 final static int m = 456;就会存放一个ConstantValue,其指向常量456;

8.methods_count  methods

方法表集合,与字段表的结构基本一样的,除了access_flags标志值有变化,变化如下:

标志名称 标志值
ACC_PUBLIC 0X0001
ACC_PRIVATE 0X0002
ACC_PRITECTED 0X0004
ACC_STATIC 0X0008
ACC_FINAL 0X0010
ACC_SYNCHRONIZED 0X0020
ACC_BRIDGE 0X0040
ACC_VARARGS 0X0080
ACC_NATIVE 0X0100
ACC_ABSTRACT 0X0400
ACC_STRICT 0X0800
ACC_SYNTHETIC 0X1000

如果父类方法没有在子类中被重写,那么方法表中不会出现父类的方法信息;另外也有可能会出现编译器自动添加的方法,如<clinit>(类的构造方法)<init>(实例构造方法)

方法具体的代码被编译成字节码指令,存放在方法属性表内一个名为Code的属性里面

9.attributes_count  attributes

属性表,包括很多个属性,例如Code,constantValue,Exceptions(可能抛出的异常种类和数量 ,throws)等等

原文地址:https://www.cnblogs.com/xiao-ji-xiang/p/9837445.html