本章节开始学习属性表相关信息,上一节找到的main()方法的字节码就出现在属性表中,属性表可谓是个大杂烩,里面存储了各式各样的信息。下面我们就来详细讨论讨论。
解析属性表
AttributeInfo接口
和常量池类似,各种属性表达的信息也各不相同,因此无法用同一的结构来定义。不同之处在于,常量是由Java虚拟机规范严格定义的,共有14种。但是属性是可以扩展的,不同的虚拟机实现可以定义自己的属性类型,所以Java虚拟机规范没有使用tag,而是使用属性名来区别不同的属性。属性的结构定义如下:
|
|
attribute_name_index为属性名常量池索引,指向常量池中的CONSTANT_Utf8_info常量。attribute_length表示属性数据的字节数,info[attribute_length]表示属性数据。相关代码位于attribute_info.go文件中:
像常量池一样,还是要先去实现各个属性结构体,再回过来写读取属性表入口。
Java虚拟机规范预订定义了23中属性,按照用途可以分为三组。第一组属性是实现Java虚拟机所必须的,共5种;第二组属性时Java类库所必须的,共有12种;第三组属性主要提供给工具使用,共有6种。第三组属性是可选的,也就是说可以不出现在class文件中。我们重点挑8个学习下,下面列举这八种属性属性出现的Java版本、分组以及他们在class文件中的位置:(完整的23种都列出来篇幅太长了,在本页源码注释部分可以查看到)
属性名 | Java SE | 分组 | 位置 |
---|---|---|---|
Deprecated | 1.1 | 3 | ClassFile, field_info, method_info |
Synthetic | 1.1 | 2 | ClassFile, field_info, method_info |
SourceFile | 1.0.2 | 3 | ClassFile |
ConstantValue | 1.0.2 | 1 | field_info |
Code | 1.0.2 | 1 | method_info |
Exceptions | 1.0.2 | 1 | method_info |
LineNumberTable | 1.0.2 | 3 | Code |
LocalVariableTable | 1.0.2 | 3 | Code |
Deprecated和Synthetic
Deprecated和Synthetic是最简单的两种属性,仅起标记作用,不包含任何数据。这两种属性都是JDK1.1引入的,可以出现在ClassFile, field_info, method_info,这里说的ClassFile,其实意思就是出现在ClassFile的attribute_info中。它们的结构如下:
由于不包含任何数据,所以attribute_length的值必须为0。Deprecated属性用于指出类、接口、字段或方法已经不建议使用。Synthetic属性用来标记源文件中不存在、有编译器生成的类成员,引入Synthetic属性主要是为了支持嵌套类和嵌套接口。相关代码位于attr_marker.go文件中:
SourceFile属性
SourceFile是可选定长属性,只会出现在ClassFile结构中,用于指出源文件名。其结构定义如下:
attribute_length的值必须是2,attribute_name_index和sourcefile_index都是常量池索引。相关代码位于attr_source_file.go文件中:
下面来看看class文件:
前两个字节attribute_name_index为0x002F,转换成十进制为47。查看常量池,第47个是CONSTANT_Utf8_info常量结构体,字面值正是SourceFile。虽然attribute_length占4个字节,但是SourceFile属性中该值固定为2,所以直接看最后2个字节0x0030,转换成十进制为48。查看常量池第48个:
图中可以看出是CONSTANT_Utf8_info常量结构体,字面值为ClassFile.java,正是源文件名。
ConstantValue
ConstantValue是定长属性,只会出现在field_info结构中,用于表示常量表达wenjian式的值,其结构如下:
attribute_length的值必须为2,attribute_name_index和constantvalue_index都是常量池索引,但constantvalue_index具体指向哪种常量因字段类型而异。下表给出字段类型和常量类型的对应关系:
字段类型 | 常量类型 |
---|---|
long | CONSTANT_Long_info |
float | CONSTANT_Float_info |
double | CONSTANT_Double_info |
int、short、char、byte、boolean | CONSTANT_Integer_info |
String | CONSTANT_String_info |
相关代码位于attr_constant_value.go文件中:
下面看下FLAG字段的class文件:
可以清楚地看出,FLAG中有一个attribute,attribute_name_index为0x0009,常量池第9个正是ConstantValue。attribute_length值固定为2,那直接看最后两个字节0x000A,指向常量池第10个CONSTANT_Integer_info常量。
下节继续学习属性相关信息。。。