首先声明,本文只是使用类文件的平常情况进行说明,对一些特殊情况不深入研究.(比如:int常量多大才会进入常量池而不是嵌入到代码中,为什么接口中的方法被实现后不出现在常量池中等等).首先,对类文件的格式做个总括;然后分别对每个部分进行详细说明;最后使用一个简单的类文件作为例子进行说明.
类文件的信息如以下格式排列:
Magic Num->minor number->major number->constant_pool_count->constant_pool->access_flags->this_class->super_class->interfaces_count->interfaces->fields_count->fields->methods_count->methods->attributes_count->attributes
Magic Num:占4个字节,”CAFE BABE”代表class文件符合JVM格式.
minor number和major number:它们组合表示语言的版本.如”0034”对应”52.0”,前两个字节是minor number,代表小数点后的数字;后两个字节是major number,代表小数点前的数字.
constant_pool_count:2个字节,代表常量池的长度+ 1.
这里需要说明一下,constant_pool,interfaces,fields,methods和attributes这几个区域阅读步骤如下:
1)查看X_count的值(除了常量池,其他值直接代表长度),确定区域的长度,每个区域都有对应长度的信息.如constant_pool_count = 20,那么常量池具有19个常量.
2)每个信息都有自己的类型,信息的开头都是关于类型的值.通过信息的开头可以分割开各个信息.
3)阅读每个分割的信息
constant_pool:长度不限,包含constant_pool_count - 1个常量信息.以下列举常用的常量
常量类型
常量格式
说明
CONSTANT_Utf8_info
tag(01) length content
每种常量都具有一个tag;说明常量的类型.length是常量的长度,2个字节;content是utf8常量的内容.每一个字节代表一个utf8字符.
CONSTANT_Integer_info
tag(03) bytes
bytes是int常量的值,占4个字节
CONSTANT_Float_info
tag(04) bytes
bytes是float常量的值,占4个字节
CONSTANT_Long_info
tag(05) bytes
bytes是long常量的值,占8个字节
CONSTANT_Double_info
tag(06) bytes
bytes是double常量的值,占8个字节
CONSTANT_Class_info
tag(07) index
index指向类全限定名的tag
CONSTANT_String_info
tag(08) index
index指向字符串字面量的tag
CONSTANT_Fieldref_info
tag(09) index0 index1
index0指向声明该字段的Class_info,index1指向该字段的NameAndType_info
CONSTANT_Methodref_info
tag(10) index0 index1
index0指向声明该方法的Class_info的tag, index1指向该方法的NameAndType_info的tag
CONSTANT_NameAndType_info
tag(12) index0 index1
index0指向name的tag,index1指向type的tag
备注:
1)Class_info,String_info,Fieldref_info,Methodref_info和NameAndType_info可以看作是对象,index对应属性.Utf8_info,Integer_info,Float_info, Long_info,Double_info可以看作是基本类型.
2)NameAndType的type的utf8值在Fieldref和Methodref中具有不同的表示.
Methodred中的type代表方法的说明,具有两个部分和三种类型,分别如下:
void m() ()V //空类型,构造方法的返回值也为void
String toString() ()Ljava/lang/String //引用类型,L代表引用
long(int[] arr1,int num,long length) ([IIJ)J //基本类型,I代表整数,J代表长整数.数组需要在前面加”[”.
所有基本类型的字母在fields中展示.
Fieldref中的type代表常量的类型的类全限定名.
3)tag默认是1个字节,index默认是2个字节
access_flags:2个字节,代表类信息.相当于bitmap,每一位代表一项信息,信息如下:
位置名称
位置
作用
ACC_PUBLIC
0x0001
该类是否是public类
ACC_FINAL
0x0010
该类是否是final类
ACC_SUPER
0x0020
编译器会自动设置为true
ACC_INTERFACE
0x0200
该类是否是接口
ACC_ABSTRACT
0x0400
该类是否是接口或者抽象类
ACC_SYNTHETIC
0x1000
编译器自动生成
ACC_ANNOTATION
0x2000
该类是否是注解
ACC_ENUM
0x4000
该类是否是枚举类
this_class:2个字节,指向该类在常量池中的Class_Info
super_class:2个字节,指向该类的父类在常量池中的Class_Info
interfaces_count:2个字节,该类中实现的接口数量
interfaces:2个字节,包含interfaces_count个接口信息,每个接口信息直指向常量池中该接口的Class_Info的偏移地址
fields_count:2个字节,该类中属性,以及该类方法调用过的其他类的属性数量
fields:通常为6个字节,包含fields_count个属性信息,每个属性包含以下内容:
access_flags:2个字节,代表属性修饰信息,相当于bitmap,每一位代表一项信息,信息如下:
位置名称
位置
ACC_PUBLIC
0x0001
ACC_PRIVATE
0x0002
ACC_PROTECTED
0x0004
ACC_STATIC
0x0008
ACC_FINAL
0x0010
ACC_VOLATILE
0x0040
ACC_TRANSIENT
0x0080
ACC_SYNTHETIC
0x1000
ACC_ENUM
0x4000
name_index:2个字节,属性名在常量池中的偏移地址
descriptor_index:2个字节,属性类型符号在常量池中的偏移地址,所有属性类型如下所示
符号
属性类型
B
byte类型
C
char类型
D
double类型
F
float类型
I
int类型
J
long类型
S
short类型
Z
boolean类型
V
void类型
L
Object类型.另外,如果是继承Object的需要加上类全限定名
[
一维数组,需要放在其他类型前面
[[[...
多维数组
注意:常量池中只会出现该类中使用过的属性类型对应的符号
另外,attributes_count和attributes不常用,这里不做列举.
methods_count:2个字节,该类中方法以及该类方法中调用过的其他类的方法数量
methods:通常字节数不固定,包含methods_count个方法信息,每个方法包含以下内容:
access_flags:2个字节,代表方法修饰信息,相当于bitmap,每一位代表一项信息,常用的信息如下:
位置名称
位置
ACC_PUBLIC
0x0001
ACC_PRIVATE
0x0002
ACC_PROTECTED
0x0004
ACC_STATIC
0x0008
ACC_FINAL
0x0010
ACC_SYNCHRONIZED
0x0020
ACC_NATIVE
0x0100
ACC_ABSTRACT
0x0400
ACC_SYNTHETIC
0x1000
name_index:2个字节,方法名在常量池中的偏移地址
descriptor_index:2个字节,该类对应的NameAndType在常量池中的偏移地址
attributes_count:2个字节,代表该方法中attributes的数量
attribute属性,方法都可能存在,可以认为是额外信息.它也可以在类文件中独立存在,通常保存源文件名.
attributes:方法中的attribute,通常包含一个Code结构(一种attribute结构),它代表方法中的代码,Code结构如下:
attribute_name_index:2个字节,代表该attribute名字在常量池中的偏移地址.
attribute_length:4个字节,该attribute的长度
max_stack:2个字节,暂且不明功能
max_local:2个字节,方法中局部变量数量
code_length:4个字节,代码长度
code:code_length个字节,存储方法中代码的字节码
exception_table_length:2个字节,异常表的长度
exception_table:exception_table_length个字节,存储方法中的异常
attributes_count:2个字节,Code中的attribute数量.通常包含LineNumberTable和LocalVariableTable,暂且不深入
attributes:包含attributes_count个attribute
最后是class文件的attribtues,结构与上面所说的相似,暂且不深入.