本章节继续学习ClassFile中各项所代表的含义。
接口索引表
类和超类索引后面时接口索引表,表中存放的也是常量池索引。ClassFile.class没有实现接口,所以接口表是空的:
在class_file.go文件中添加读取接口索引表的方法:
字段表(field_info)和方法表(method_info)
接口索引表之后是字段表和方法表,分别存储字段和方法信息。field_info和method_info的基本结构大致相同,差别仅在于属性表,下面时Java虚拟机规范给出的field_info结构定义:
method_info的结构上述一样,仅在access_flags和attribute_info的可选项中有所区别。为了避免重复代码,所以用一个结构体同一表示字段表和方法表,位于member_info.go文件中,结构体名为MemberInfo:
MemberInfo中有4个字段和field_info完全对应,请中cp字段用于保存常量池指针,后面会用到。我们下面来看下field_info中各项的含义。
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | access_flags | 1 | 字段和方法的访问修饰符 |
u2 | name_index | 1 | 常量池索引,代表字段的简单名称 |
u2 | descriptor_index | 1 | 常量池索引,代表字段和方法的描述符 |
u2 | attributes_count | 1 | 字段和方法的额外附加属性数量 |
attribute_info | attributes[attributes_count] | attributes_count | 字段和方法的额外的附加属性 |
访问修饰符和上一节讲的类访问符标志很相似,下表列举下字段的访问标志可选项:
标志名称 | 标志值 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 字段是否为public |
ACC_PRIVATE | 0x0002 | 字段是否为private |
ACC_PROTECTED | 0x0004 | 字段是否为protected |
ACC_STATIC | 0x0008 | 字段是否为static |
ACC_FINAL | 0x0010 | 字段是否为final |
ACC_VOLATILE | 0x0040 | 字段是否为volatile |
ACC_TRANSIENT | 0x0080 | 字段是否为transient |
ACC_SYNTHETIC | 0x1000 | 字段是否由编译器自动产生 |
ACC_ENUM | 0x4000 | 字段是否是enum类型 |
在实际情况中访问标志的使用时有限制的,比如ACC_PUBLIC、ACC_PRIVATE和ACC_PROTECTED三个标志只能选其一,ACC_FINAL和ACC_VOLATILE只能选其一等等,这些都是由Java本身的语言规范所决定的。
方法表的访问修饰符和字段表访问修饰符类似:
标志名称 | 标志值 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 方法是否为public |
ACC_PRIVATE | 0x0002 | 方法是否为private |
ACC_PROTECTED | 0x0004 | 方法是否为protected |
ACC_STATIC | 0x0008 | 方法是否为static |
ACC_FINAL | 0x0010 | 方法是否为final |
ACC_SYNCHRONIZED | 0x0020 | 方法是否为synchronized |
ACC_BRIDGE | 0x0040 | 方法是否是由编译器产生的桥接方法 |
ACC_VARARGS | 0x0080 | 方法是否接受不定参数 |
ACC_NAVIVE | 0x0100 | 方法是否为native |
ACC_ABSTRACT | 0x0400 | 方法是否为abstract |
ACC_STRICTFP | 0x0800 | 方法是否为strictfp |
ACC_SYNTHETIC | 0x1000 | 方法是否由编译器自动产生 |
ClassFile.class的字段表和方法表如下:
在member_info.go文件中添加读取方法:
在class_file.go中添加读取字段表和方法表的方法:
下节继续…