首先声明,本文只是使用类文件的平常情况进行说明,对一些特殊情况不深入研究.(比如: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,结构与上面所说的相似,暂且不深入.