一、class 文件数据项的类型
u1
u2
u4
u8
...
二、class 文件的数据项
类型 | 名称 | 数量 |
---|---|---|
u4 | magic | 1 |
u2 | minor_version | 1 |
u2 | major_version | 1 |
u2 | constant_pool_count | 1 |
cp_info | constant_pool | constant_pool_count - 1 |
u2 | access_flags | 1 |
u2 | this_class | 1 |
u2 | super_class | 1 |
u2 | interfaces_count | 1 |
u2 | interfaces | interfaces_count |
u2 | fields_count | 1 |
field_info | fields | fields_count |
u2 | methods_count | 1 |
method_info | methods | methods_count |
u2 | attribute_count | 1 |
attribute_info | attributes | attributes_count |
三、各数据项
1、魔数(magic)
4 个字节,固定为 0XCAFEBABE。
2、次版本号(minor_version)
2 个字节。
3、主版本号(major_version)
2 个字节。
4、常量池大小(constant_pool_count)
2 个字节。
5、常量池(constant_pool)
constant_pool_count-1 个 cp_info。
索引为 0 的常量池项空白,引用索引为 0 的常量池项则表示不引用任何常量池项。
常量池数据项类型:
常量池中数据项类型 | 类型标志 | 类型描述 |
---|---|---|
CONSTANT_Utf8 | 1 | UTF-8 编码的 Unicode 字符串 |
CONSTANT_Integer | 3 | int 类型字面值 |
CONSTANT_Float | 4 | float 类型字面值 |
CONSTANT_Long | 5 | long 类型字面值 |
CONSTANT_Double | 6 | double 类型字面值 |
CONSTANT_Class | 7 | 对一个类或接口的符号引用 |
CONSTANT_String | 8 | String 类型字面值 |
CONSTANT_Fieldref | 9 | 对一个字段的符号引用 |
CONSTANT_Methodref | 10 | 对一个类中声明的方法的符号引用 |
CONSTANT_InterfaceMethodref | 11 | 对一个接口中声明的方法的符号引用 |
CONSTANT_NameAndType | 12 | 对一个字段或方法的部分符号引用 |
class 文件的特殊字符串:
i. 类的全限定名:java/lang/Object
ii. 描述符:
基本数据类型和 void 类型 | 类型的对应字符 |
---|---|
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
boolean | Z |
void | V |
引用类型:“L”+ 类型的全限定名 +“;”
数组类型:若干个“[”+ 数组中元素类型的对应字符串
方法:(参数 1 类型 参数 2 类型 参数 3 类型 ...)返回值类型 //各个参数类型之间没有空格, 参数列表和返回值类型之间也没有空格
iii. 特殊方法的方法名
构造方法:<init>
静态代码块:<clinit>
- CONSTANT_Utf8
一个 CONSTANT_Utf8_info |
---|
tag(1 个字节) |
length(2 个字节) |
bytes(length 个字节) |
CONSTANT_Utf8 类型数据项可表示:程序中的字符串常量, 类型的全限定名, 方法和字段的名称, 方法和字段的描述符, 属性相关字符串。
- CONSTANT_NameAndType
一个 CONSTANT_NameAndType_info |
---|
tag(1 个字节) |
name_index(名称) |
descriptor_index(描述符) |
一个 CONSTANT_NameAndType_info 就表示了一个被调用的方法(如父类的构造函数)或一个被使用的字段。
仅在类中定义的字段或方法没有相应的 CONSTANT_NameAndType_info。
- CONSTANT_Integer
一个 CONSTANT_Integer_info |
---|
tag(1 个字节) |
bytes(4 个字节) |
- CONSTANT_Float
一个 CONSTANT_Float_info |
---|
tag(1 个字节) |
bytes(4 个字节) |
- CONSTANT_Long
一个 CONSTANT_Long_info |
---|
tag(1 个字节) |
bytes(8 个字节) |
- CONSTANT_Double
一个 CONSTANT_Double_info |
---|
tag(1 个字节) |
bytes(8 个字节) |
- CONSTANT_String
一个 CONSTANT_String_info |
---|
tag(1 个字节) |
string_index(2 个字节) |
- CONSTANT_Class
一个 CONSTANT_Class_info 是对类或者接口的符号引用(包括数组)。
一个 CONSTANT_Class_info |
---|
tag(1 个字节) |
name_index(类的全限定名,2 个字节) |
- CONSTANT_Fieldref
该数据项表示对一个字段的符号引用, 可以是对本类中的字段的符号引用, 也可以是对其他类中的字段的符号引用, 可以是对成员变量字段的符号引用, 也可以是对静态变量的符号引用。
字段必须被使用才会有相应的符号引用,只在类中定义是没有符号引用的。
一个 CONSTANT_Fieldref_info |
---|
tag(1 个字节) |
class_index(2 个字节) |
name_and_type_index(2 个字节) |
- CONSTANT_Methodref
对一个类中方法的符号引用, 可以是对本类中的方法的符号引用, 也可以是对其他类中的方法的符号引用, 可以是对成员方法的符号引用, 也可以是对静态方法的符号引用,但是不会是对接口中的方法的符号引用。
方法必须被调用才会有相应的符号引用,只在类中定义是没有符号引用的。
一个 CONSTANT_Methodref_info |
---|
tag(1 个字节) |
class_index(2 个字节) |
name_and_type_index(2 个字节) |
- CONSTANT_InterfaceMethodref
表示对一个接口方法的符号引用。
一个 CONSTANT_InterfaceMethodref_info |
---|
tag(1 个字节) |
class_index(2 个字节) |
name_and_type_index(2 个字节) |
6、当前类(或者接口)的访问修饰符(access_flags)
2 个字节
志名 | 标志值 | 标志含义 | 针对的对像 |
---|---|---|---|
ACC_PUBLIC | 0x0001 | public 类型 | 所有类型 |
ACC_FINAL | 0x0010 | final 类型 | 类 |
ACC_SUPER | 0x0020 | 使用新的 invokespecial 语义 | 类和接口 |
ACC_INTERFACE | 0x0200 | 接口类型 | 接口 |
ACC_ABSTRACT | 0x0400 | 抽象类型 | 类和接口 |
ACC_SYNTHETIC | 0x1000 | 该类不由用户代码生成 | 所有类型 |
ACC_ANNOTATION | 0x2000 | 注解类型 | 注解 |
ACC_ENUM | 0x4000 | 枚举类型 | 枚举 |
7、对当前类的描述(this_class)(类的全限定名)
2 个字节(对一个 CONSTANT_Class_info 数据项的索引)。
8、对当前类的超类的描述(super_class)
2 个字节(对一个 CONSTANT_Class_info 数据项的索引)。
9、当前类所实现的接口的数量(interfaces_count)
注意, 只有当前类直接实现的接口才会被统计, 如果当前类继承了另一个类, 而另一个类又实现了一个接口, 那么这个接口不会统计在当前类的 interfaces_count 中。
10、当前类所实现的接口(interfaces)
interfaces_count 个 u2。
每个数据项指向常量池中的一个 CONSTANT_Class_info。
11、当前的类中定义的字段的个数(fields_count)
2 个字节。
注意, 这里包括静态字段, 但不包括从父类继承的字段。 如果当前 class 文件是由一个接口生成的, 那么这里的 fields_count 描述的是接口中定义的字段, 我们知道, 接口中定义的字段默认都是静态的。此外要说明的是, 编译器可能会自动生成字段, 也就是说, class 文件中的字段的数量可能多于源文件中定义的字段的数量。 举例来说, 编译器会为内部类增加一个字段, 这个字段是指向外围类的对象的引用。
12、当前的类中定义的字段(fields)
field_count 个 field_info。
field 结构:
一个 field |
---|
access_flags |
name_index |
descriptor_index |
attributes_count |
attributes |
- 标志位(access_flags)
2 个字节。
标志位名称 | 值 | 含义 | 设定者 |
---|---|---|---|
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 | 类 |
-
字段名(name_index)
2 个字节。
指向常量池中的一个 CONSTANT_Utf8_info 数据项。 -
描述符(descriptor_index)
2 个字节。
指向常量池中的一个 CONSTANT_Utf8_info 数据项。 -
属性数量(attributes_count)
2 个字节。 -
属性(attributes)
可以出现在 filed_info 中的属性有三种, 分别是 ConstantValue, Deprecated, 和 Synthetic。
13、当前的类中定义的方法的个数(methods_count)
标志位名称 | 标志值 | 设定含义 | 设定者 |
---|---|---|---|
ACC_PUBLIC | 0x0001 | 方法设为 public | 类和接口 |
ACC_PRIVATE | 0x0002 | 方法设为 private | 类 |
ACC_PROTECTED | 0x0004 | 方法设为 protected | 类 |
ACC_STATIC | 0x0008 | 方法设为 static | 类 |
ACC_FINAL | 0x0010 | 方法设为 final | 类 |
ACC_SYNCHRONIZED | 0x0020 | 方法设为 sychronized | 类 |
ACC_NATIVE | 0x0100 | 方法设为 native | 类 |
ACC_ABSTRACT | 0x0400 | 方法设为 abstract | 类和接口 |
ACC_STRICT | 0x0800 | 方法设为 strictFP | 类和接口的方法 |
可以出现在 method_info 中的属性分别是 Code, Deprecated, Exceptions 和 Synthetic。
14、attribute_count
15、attribute
SourceFile // 内部类的,描述其外部类
InnerClasses // 外部类的,描述其内部类
Synchetic // 表示不是由用户代码生成的,是由编译器自动添加的,可以修饰方法和字段,例如,如果一个类不定义构造方法, 那么编译器会自动添加一个无参数的构造方法, 如果定义了静态字段或静态代码块, 还会根据具体情况, 增加静态初始化方法
ConstantValue // 修饰字段
Deprecated // 修饰字段和方法
符号引用:
最基本的 UTF-8 编码的 Unicode 字符串:
CONSTANT_Utf8
字面量:
CONSTATN_Integer
CONSTATN_Long
CONSTATN_Float
CONSTANT_Double
CONSTANT_String
符号引用:
CONSTANT_Class // 类或接口的符号引用
CONSTATN_NameAndType // 一个字段或方法的部分符号引用
// 以下三种符号引用由上面两种符号引用组成
CONSTATN_Fieldref // 字段的符号引用
CONSTANT_Methodref // 类中声明的方法的符号引用
CONSTANT_InterfaceMethodref // 接口中声明的方法的符号引用
#1、#2 等表示在常量池中的下标
#0 表示不引用任何常量池的项,比如
直接引用:
就是偏移量,根据这些偏移量可以找到相应的类,并在类的内存区域中找到对应的字段或方法。
class 文件其实就存了两样东西:字面量和符号引用。
参考:
《深入理解 Java 虚拟机》
《Java 虚拟机规范(JavaSE8)》
http://blog.csdn.net/brave2211/article/category/1593711/1
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于