文章目录
- 1. 什么是class文件?
- 2. class文件的数据类型
- 3. class文件结构
- 3.1 magic,魔数,u4
- 3.2 minor_version,次版本号,u2
- 3.3 major_version,主版本号,u2
- 3.4 constat_pool_count和constant_pool,常量池
- 3.5 access_flags,类访问标识符
- 3.6 this_class和super_class,类和父类的全限定名
- 3.7 interfaces_count和interfaces,接口的数量和接口名
- 3.8 fields_count和fields,字段的数量和字段表
- 3.9 methods_count和methods,字段的数量和字段表
- 3.10 attributes_count和attributes,字段的数量和字段表
1. 什么是class文件?
class文件就是将java源代码编译后形成的,可被java虚拟机加载运行的文件。
对于Java虚拟机来说,只要是满足Java虚拟机规范的class文件都可以被加载。
2. class文件的数据类型
class文件的数据结构只有 无符号数 和 表。对于class文件来说,就像一列整齐紧密的货物,一个字节一个字节的排列下去。
黄框 = 1个字节 = 8位 👇
无符号数通过字节为基本单位划分为: u1 ,u2 ,u4 ,u8
表结构则是通过组合若干的无符号数和表结构组合而成
3. class文件结构
文件的具体格式列表如下。
class文件就是按照这样的排列依次的排下去。
可以注意到其中有些类型 如 cp_info , field_info 等,代表的是,这是一个表结构。
3.1 magic,魔数,u4
magic 称为魔数,标志这是一个class文件。
3.2 minor_version,次版本号,u2
标志class文件的次版本号。
3.3 major_version,主版本号,u2
标志class文件的主版本号。
3.4 constat_pool_count和constant_pool,常量池
constat_pool_count代表常量池的大小,它本身占2个字节,因此可以推断常量池可以存放 2^16 次方个常量。
constant_pool是一个表,他的结构如下:
而tag具体的取值和后续结构如下图:
3.5 access_flags,类访问标识符
这个标识符的作用是记录类的访问限定,如 public , final 等等的信息,共有如下几种:
3.6 this_class和super_class,类和父类的全限定名
this_class 和 super_class 都是2个字节大小,值指向的是常量池的 CONSTANT_Class_info 结构 ,而 CONSTANT_CLass_info 指向的是 CONSTANT_Utf8_info 的字符串常量。
3.7 interfaces_count和interfaces,接口的数量和接口名
interfaces_count 代表下面将要列举出多少个 interfaces_info 结构的表。
每个interfaces 指向的是 常量池的 CONSTANT_Class_info 结构,而 CONSTANT_CLass_info 指向的是 CONSTANT_Utf8_info 的字符串常量就代表这个接口的全限定名。
3.8 fields_count和fields,字段的数量和字段表
可以观察到,每个表前面都会有一个表数量的计数器。fields_count就标志这下面会出现多少个一fields_info表结构出现的字段内容。
fields_info的结构如下:
3.9 methods_count和methods,字段的数量和字段表
方法表和字段表类似,有两个差别:
- 访问标志的差别,因为字段的访问标志和方法的访问标志不相同,如字段不能有synchronized,方法不能有volatile。
- 属性表的差别,和访问标志差别相同,属性也有只能字段使用的,和只能方法使用的。
如下图:
标志名称 | 对应修饰符 | 字段是否可用 | 方法是否可用 |
---|---|---|---|
ACC_PUBLIC | public | ✔ | ✔ |
ACC_PRIVATE | private | ✔ | ✔ |
ACC_PROTECTED | protected | ✔ | ✔ |
ACC_STATIC | static | ✔ | ✔ |
ACC_FINAL | final | ✔ | ✔ |
ACC_VOLATILE | volatile | ✔ | × |
ACC_TRANSIENT | transient | ✔ | × |
ACC_SYNTHETIC | 是否由编译器自动产生 | ✔ | ✔ |
ACC_ENUM | enum | ✔ | × |
ACC_SYNCHRONIZED | synchronized | × | ✔ |
ACC_VARARGS | 是否接收不确定参数 | × | ✔ |
ACC_NATIVE | native | × | ✔ |
ACC_ABSTRACT | abstract | × | ✔ |
ACC_STRICT | strictfp | × | ✔ |
ACC_BRIDGE | 是否由编译器产生桥接方法 | × | ✔ |
从中就可以看出字段和方法可使用的限定符有哪些。
3.10 attributes_count和attributes,字段的数量和字段表
属性表也像常量表一样,有多种不同类型,不过区别就在于,属性表的类型标志不再如常量标志那样是1-11的数字,而是一个u2大小,指向常量池的一个字符串。
整个结构的大小就等于 :
a
t
t
r
i
b
u
t
e
_
n
a
m
e
_
i
n
d
e
x
+
a
t
t
r
i
b
u
t
e
_
l
e
n
g
h
t
+
i
n
f
o
×
a
t
t
r
i
b
u
t
e
_
l
e
n
g
t
h
attribute\_name\_index + attribute\_lenght + info × attribute\_length
attribute_name_index+attribute_lenght+info×attribute_length
属性的类型主要有如下几种:
其中最为重要的是Code这个属性表,其中包含了方法中代码所编译而成的字节码指令集。