根据asm对字节码的解析,可以分析出.class文件的字节码结构
结构示意图如下
- 4个byte为cafe babe,2个byte为minor 和major
- 常量池分两部分,2个byte的常量池大小和内容
- 2个byte的access flag,2个byte的class名,2个byte的super class名,2个byte的interface数量,及interface
- 2个byte的field数量及field内容
- 2个byte的method数量及method内容
- 2个byte的i值,2个byte的attribute名,4个byte的attribute长度及attribute内容
下面分别来看各个部分
cafe babe为魔数,写死的,minor version和major version也好理解
常量池部分
常量池大小即常量的个数,具体的每个常量部分第一个byte为类型,后面为常量内容,类型总共有17种,根据占据byte个数不同可以分为2类,固定长度的和可变长度的
其中固定长度的有4种
- 4个byte:
- CONSTANT_FIELDREF_TAG
- CONSTANT_METHODREF_TAG
- CONSTANT_INTERFACE_METHODREF_TAG
- CONSTANT_INTEGER_TAG
- CONSTANT_FLOAT_TAG
- CONSTANT_NAME_AND_TYPE_TAG
- CONSTANT_DYNAMIC_TAG
- CONSTANT_INVOKE_DYNAMIC_TAG
- 8个byte:
- CONSTANT_LONG_TAG
- CONSTANT_DOUBLE_TAG
- 3个byte:
- CONSTANT_METHOD_HANDLE_TAG
- 2个byte:
- CONSTANT_CLASS_TAG
- CONSTANT_STRING_TAG
- CONSTANT_METHOD_TYPE_TAG
- CONSTANT_PACKAGE_TAG
- CONSTANT_MODULE_TAG
可变长度的只有一种CONSTANT_UTF8_TAG
其占用byte情况为:2个byte+2个byte所指定的长度个byte,两种情况如下图
基本信息
access flag占2个byte,class name和super class都占2个byte,其值为常量池中的字符串索引(后面简称常量索引),也就是说具体的字符串需要回常量池中查找,interface数量占2个byte,后续每个interface名也占2个byte,也为常量索引
field&method部分
- 2个byte的access flag
- 2个byte的name,值为常量索引
- 2个byte的描述
- 2个byte的attribute数量
- 每个attribute有2个byte的name,值为常量索引,4个byte的属性长度,及对应个byte的attribute
attribute部分
attribute基本格式为2个byte的name,值为常量索引,4个byte的attribute内容长度
根据attribute name的不同,attribute结构总共有17种(asm1.7中的)
- SOURCE_FILE为2个byte,值为常量索引
- INNER_CLASSES为2个byte的内部类个数,每个内部类为2个byte name, 2个byte的外部类,2个byte的内部类,它们都为常量索引,2个byte的access flag
- ENCLOSING_METHOD为2个byte的外部类名,值为常量索引,2个byte的方法名eclosing的话,值为常量索引,此常量索引偏移2个byte即为descripter
- NEST_HOST为2个byte的类名,值为常量索引
- NEST_MEMBERS为2个byte的个数,每个MEMBER为2个byte的常量索引
- SIGNATURE为2个byte的类泛型描述,值为常量索引
- DEPRECATED和SYNTHETIC都可以不占其它byte,描述access flag信息
- SOURCE_DEBUG_EXTENSION为attribute length个byte长度,为字符串(此处不是常量池索引)
- MODULE_MAIN_CLASS为2个byte的main class,为字符串索引
- MODULE_PACKAGES为2个byte的package count,每个package为2个byte的常量索引
- BOOTSTRAP_METHODS拼装成attribute的字节数组
- MODULE为2个byte的name, 为字符串索引,2个byte的access flag,为字符串索引,两个byte的version,如果MODULE_MAIN_CLASS不为空,则接下来有require、export、open、use、provide几个模块,这几个模块都是2个byte的长度加内容
- 每个require长度固定,2个byte的name为字符串索引,2个byte的flag为字符串索引,2个byte的version
- 每个export&open由2个byte的name为字符串索引,2个byte的flag,2个byte的exportTo&openTo的数量,每个exportTo&openTo有2个byte的字符串索引
- 每个use长度固定,2个byte的name为字符串索引
- 每个provides由2个byte的name为字符串索引,2个byte的providesWith数量,每个providesWith有2个byte的字符串索引
- RUNTIME_INVISIBLE_ANNOTATIONS&RUNTIME_VISIBLE_ANNOTATIONS为2个byte的annotation数量,每个annotation有description为2个byte的字符串索引,及2个byte的ElementValuePair数量,每个ElementValuePair由2个byte的字符串索引的elementName及elementValue组成,elementValue内容中有1个byte为类型,除去类型之后
- 如果类型为’e’,说明为ENUM,则内容为4个byte
- 如果类型为’@’,说明为Annotation,内容会递归判断
- 如果类型为’[’,说明为数组,内容则会判断其元素属性
- 其它的类型内容都为2个byte
- RUNTIME_VISIBLE_ANNOTATIONS&RUNTIME_INVISIBLE_TYPE_ANNOTATIONS跟RUNTIME_INVISIBLE_ANNOTATIONS类似,只是每个annotation在description前多了1个byte的targetType,根据targetType间隔不同byte数,又有1个byte的pathLength,及2*pathLength个byte的targetPath