访问标识/类索引/父类索引/接口索引
Class 文件结构中的索引区域
Class 文件中,访问标识和各类索引决定了类的身份和继承关系。
类索引(this_class)
类索引指向常量池中的一个 CONSTANT_Class 常量,表示当前类:
this_class (u2):
│
└──▶ constant_pool[this_class] = CONSTANT_Class_info
│
└──▶ name_index → CONSTANT_Utf8 = "com/example/User"父类索引(super_class)
父类索引指向常量池中的一个 CONSTANT_Class 常量,表示父类:
super_class (u2):
│
└──▶ constant_pool[super_class] = CONSTANT_Class_info
│
└──▶ name_index → CONSTANT_Utf8 = "java/lang/Object"特殊情况
| 场景 | super_class 值 | 说明 |
|---|---|---|
class User {} | 指向 java/lang/Object | 默认继承 Object |
class User extends Person {} | 指向 Person | 显式指定父类 |
public interface I {} | 值为 0 | 接口的父类没有意义 |
public interface I extends A, B {} | 值为 0 | 接口也用 0 |
接口索引集合(interfaces)
接口索引集合存储当前类实现的所有接口:
interfaces_count (u2):
│
└── N 个接口索引
interfaces[0] (u2):
│
└──▶ constant_pool[interfaces[0]] = CONSTANT_Class_info
│
└──▶ name_index → CONSTANT_Utf8 = "java/io/Serializable"查看接口索引
bash
javap -verbose User.class
# 输出:
# public class com.example.User implements java.io.Serializable
# ...
# interfaces count: 1
# public static final transient java.io.Serializable JNI;
# descriptor: Ljava/io/Serializable;
# ...字段表集合(fields)
基本结构
fields_count (u2): 字段数量
│
fields[]:
field_info {
u2 access_flags; // 访问标识
u2 name_index; // 字段名(指向 Utf8)
u2 descriptor_index; // 描述符(指向 Utf8)
u2 attributes_count; // 属性数量
attribute_info attributes[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 | 枚举字段 |
字段描述符
字段描述符描述字段的类型:
java
public class User {
private String name; // 描述符: Ljava/lang/String;
private int age; // 描述符: I
private boolean active; // 描述符: Z
private String[] roles; // 描述符: [Ljava/lang/String;
}查看字段表
bash
javap -verbose User.class
# 输出:
# private java.lang.String name;
# descriptor: Ljava/lang/String;
# flags: ACC_PRIVATE
#
# private int age;
# descriptor: I
# flags: ACC_PRIVATE方法表集合(methods)
基本结构
methods_count (u2): 方法数量
│
methods[]:
method_info {
u2 access_flags; // 访问标识
u2 name_index; // 方法名(指向 Utf8)
u2 descriptor_index; // 描述符(指向 Utf8)
u2 attributes_count; // 属性数量
attribute_info attributes[attributes_count];
}方法的访问标识
| 标识 | 值 | 说明 |
|---|---|---|
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_NATIVE | 0x0100 | native 方法 |
ACC_ABSTRACT | 0x0400 | abstract |
ACC_STRICT | 0x0800 | strictfp |
ACC_SYNTHETIC | 0x1000 | 编译器生成 |
方法描述符
java
// 方法描述符示例
String toString()
// → ()Ljava/lang/String;
int indexOf(String str, int fromIndex)
// → (Ljava/lang/String;I)I
void main(String[] args)
// → ([Ljava/lang/String;)V
boolean equals(Object obj)
// → (Ljava/lang/Object;)Z查看方法表
bash
javap -verbose User.class
# 输出:
# public java.lang.String toString();
# descriptor: ()Ljava/lang/String;
# flags: ACC_PUBLIC
# Code:
# stack=2, locals=1, args_size=1
# 0: aload_0
# 1: getfield #2
# 4: areturn属性表集合(attributes)
重要的预定义属性
JVM 定义了多种预定义属性,其中最重要的是 Code 属性:
| 属性名 | 说明 | 适用 |
|---|---|---|
Code | 方法的字节码 | 方法表 |
LineNumberTable | 行号表 | Code 属性 |
LocalVariableTable | 局部变量表 | Code 属性 |
LocalVariableTypeTable | 泛型局部变量表 | Code 属性 |
SourceFile | 源文件名 | 类/接口 |
SourceDebugExtension | 调试扩展 | 类/接口 |
Deprecated | 已废弃 | 字段/方法/类 |
Synthetic | 编译器生成 | 字段/方法/类 |
Signature | 泛型签名 | 类/方法/字段 |
RuntimeVisibleAnnotations | 可见注解 | 类/方法/字段 |
SourceFile 属性
记录源文件名:
bash
javap -verbose User.class | grep SourceFile
# 输出:
# SourceFile: User.javaDeprecated 属性
标记已废弃的类/方法/字段:
java
@Deprecated
public void oldMethod() { }
// 字节码中:
// Deprecated: <no information>Signature 属性
JDK 5 引入泛型后,泛型信息需要额外存储:
java
public class Container<T> {
private T value;
}
// Signature: LContainer<TT;>;本节小结
Class 文件索引结构速查:
| 字段 | 指向 | 说明 |
|---|---|---|
| this_class | CONSTANT_Class | 当前类 |
| super_class | CONSTANT_Class(值为 0 表示接口) | 父类 |
| interfaces[] | CONSTANT_Class 数组 | 实现的接口 |
| fields[] | 字段表集合 | 所有字段 |
| methods[] | 方法表集合 | 所有方法 |
| attributes[] | 属性表集合 | 附加信息 |
字段表和方法表的结构类似,都是 access_flags + name + descriptor + attributes。
下一节,我们来看 字段表/方法表/属性表集合。
