Skip to content

Commit 6abc003

Browse files
committed
Update 类文件结构.md
1 parent 4de0605 commit 6abc003

File tree

1 file changed

+55
-43
lines changed

1 file changed

+55
-43
lines changed

docs/java/jvm/类文件结构.md

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
21

3-
<!-- TOC -->
2+
<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} -->
3+
4+
<!-- code_chunk_output -->
45

56
- [类文件结构](#类文件结构)
6-
- [一 概述](#一-概述)
7-
- [二 Class 文件结构总结](#二-class-文件结构总结)
8-
- [2.1 魔数](#21-魔数)
9-
- [2.2 Class 文件版本](#22-class-文件版本)
10-
- [2.3 常量池](#23-常量池)
11-
- [2.4 访问标志](#24-访问标志)
12-
- [2.5 当前类索引,父类索引与接口索引集合](#25-当前类索引父类索引与接口索引集合)
13-
- [2.6 字段表集合](#26-字段表集合)
14-
- [2.7 方法表集合](#27-方法表集合)
15-
- [2.8 属性表集合](#28-属性表集合)
16-
- [参考](#参考)
17-
18-
<!-- /TOC -->
7+
- [一 概述](#一-概述)
8+
- [二 Class 文件结构总结](#二-class-文件结构总结)
9+
- [2.1 魔数(Magic Number)](#21-魔数magic-number)
10+
- [2.2 Class 文件版本号(Minor&Major Version)](#22-class-文件版本号minormajor-version)
11+
- [2.3 常量池(Constant Pool)](#23-常量池constant-pool)
12+
- [2.4 访问标志(Access Flags)](#24-访问标志access-flags)
13+
- [2.5 当前类(This Class)、父类(Super Class)、接口(Interfaces)索引集合](#25-当前类this-class-父类super-class-接口interfaces索引集合)
14+
- [2.6 字段表集合(Fields)](#26-字段表集合fields)
15+
- [2.7 方法表集合(Methods)](#27-方法表集合methods)
16+
- [2.8 属性表集合(Attributes)](#28-属性表集合attributes)
17+
- [参考](#参考)
18+
19+
<!-- /code_chunk_output -->
20+
1921

2022
# 类文件结构
2123

@@ -27,11 +29,13 @@ Clojure(Lisp 语言的一种方言)、Groovy、Scala 等语言都是运行
2729

2830
![java虚拟机](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/bg/desktop类文件结构概览.png)
2931

30-
**可以说`.class`文件是不同的语言在 Java 虚拟机之间的重要桥梁,同时也是支持 Java 跨平台很重要的一个原因。**
32+
可以说`.class`文件是不同的语言在 Java 虚拟机之间的重要桥梁,同时也是支持 Java 跨平台很重要的一个原因。
3133

3234
## 二 Class 文件结构总结
3335

34-
根据 Java 虚拟机规范,类文件由单个 ClassFile 结构组成:
36+
根据 Java 虚拟机规范,Class 文件通过 `ClassFile` 定义,有点类似 C 语言的结构体。
37+
38+
`ClassFile` 的结构如下:
3539

3640
```java
3741
ClassFile {
@@ -54,53 +58,61 @@ ClassFile {
5458
}
5559
```
5660

57-
下面详细介绍一下 Class 文件结构涉及到的一些组件
61+
通过分析 `ClassFile` 的内容,我们便可以知道 class 文件的组成
5862

59-
**Class文件字节码结构组织示意图** (之前在网上保存的,非常不错,原出处不明):
63+
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/java-guide-blog/16d5ec47609818fc.jpeg)
6064

61-
![类文件字节码结构组织示意图](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/类文件字节码结构组织示意图.png)
65+
下面这张图是通过 IDEA 插件 `jclasslib` 查看的,你可以更直观看到 Class 文件结构。
6266

63-
### 2.1 魔数
67+
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/java-guide-blog/image-20210401170711475.png)
68+
69+
使用 `jclasslib` 不光可以直观地查看某个类对应的字节码文件,还可以查看类的基本信息、常量池、接口、属性、函数等信息。
70+
71+
下面详细介绍一下 Class 文件结构涉及到的一些组件。
72+
73+
### 2.1 魔数(Magic Number)
6474

6575
```java
6676
u4 magic; //Class 文件的标志
6777
```
6878

69-
每个 Class 文件的头四个字节称为魔数(Magic Number),它的唯一作用是**确定这个文件是否为一个能被虚拟机接收的 Class 文件**
79+
每个 Class 文件的头 4 个字节称为魔数(Magic Number),它的唯一作用是**确定这个文件是否为一个能被虚拟机接收的 Class 文件**
7080

7181
程序设计者很多时候都喜欢用一些特殊的数字表示固定的文件类型或者其它特殊的含义。
7282

73-
### 2.2 Class 文件版本
83+
### 2.2 Class 文件版本号(Minor&Major Version)
7484

7585
```java
7686
u2 minor_version;//Class 的小版本号
7787
u2 major_version;//Class 的大版本号
7888
```
7989

80-
紧接着魔数的四个字节存储的是 Class 文件的版本号:第五和第六是**次版本号**,第七和第八是**主版本号**
90+
紧接着魔数的四个字节存储的是 Class 文件的版本号:第 5 和第 6 位是**次版本号**,第 7 和第 8 位是**主版本号**
91+
92+
每当 Java 发布大版本(比如 Java 8,Java9)的时候,主版本号都会加 1。你可以使用 `javap -v` 命令来快速查看 Class 文件的版本号信息。
8193

8294
高版本的 Java 虚拟机可以执行低版本编译器生成的 Class 文件,但是低版本的 Java 虚拟机不能执行高版本编译器生成的 Class 文件。所以,我们在实际开发的时候要确保开发的的 JDK 版本和生产环境的 JDK 版本保持一致。
8395

84-
### 2.3 常量池
96+
### 2.3 常量池(Constant Pool)
8597

8698
```java
8799
u2 constant_pool_count;//常量池的数量
88100
cp_info constant_pool[constant_pool_count-1];//常量池
89101
```
90102

91-
紧接着主次版本号之后的是常量池,常量池的数量是 constant_pool_count-1(**常量池计数器是从1开始计数的,将第0项常量空出来是有特殊考虑的,索引值为0代表“不引用任何一个常量池项”**)。
103+
紧接着主次版本号之后的是常量池,常量池的数量是 `constant_pool_count-1`**常量池计数器是从 1 开始计数的,将第 0 项常量空出来是有特殊考虑的,索引值为 0 代表“不引用任何一个常量池项”**)。
92104

93-
常量池主要存放两大常量:字面量和符号引用。字面量比较接近于 Java 语言层面的的常量概念,如文本字符串、声明为 final 的常量值等。而符号引用则属于编译原理方面的概念。包括下面三类常量:
105+
常量池主要存放两大常量:字面量和符号引用。字面量比较接近于 Java 语言层面的的常量概念,如文本字符串、声明为 final 的常量值等。而符号引用则属于编译原理方面的概念。包括下面三类常量:
94106

95-
- 类和接口的全限定名
96-
- 字段的名称和描述符
107+
- 类和接口的全限定名
108+
- 字段的名称和描述符
97109
- 方法的名称和描述符
98110

99-
常量池中每一项常量都是一个表,这14种表有一个共同的特点**开始的第一位是一个 u1 类型的标志位 -tag 来标识常量的类型,代表当前这个常量属于哪种常量类型.**
111+
常量池中每一项常量都是一个表,这 14 种表有一个共同的特点**开始的第一位是一个 u1 类型的标志位 -tag 来标识常量的类型,代表当前这个常量属于哪种常量类型.**
100112

101113
| 类型 | 标志(tag) | 描述 |
102114
| :------------------------------: | :---------: | :--------------------: |
103-
| CONSTANT_utf8_info | 1 | UTF-8编码的字符串 |
115+
| CONSTANT_utf8_info | 1 | UTF-8 编码的字符串 |
104116
| CONSTANT_Integer_info | 3 | 整形字面量 |
105117
| CONSTANT_Float_info | 4 | 浮点型字面量 |
106118
| CONSTANT_Long_info || 长整型字面量 |
@@ -115,11 +127,11 @@ ClassFile {
115127
| CONSTANT_MethodHandle_info | 15 | 表示方法句柄 |
116128
| CONSTANT_InvokeDynamic_info | 18 | 表示一个动态方法调用点 |
117129

118-
`.class` 文件可以通过`javap -v class类名` 指令来看一下其常量池中的信息(`javap -v class类名-> temp.txt` :将结果输出到 temp.txt 文件)。
130+
`.class` 文件可以通过`javap -v class类名` 指令来看一下其常量池中的信息(`javap -v class类名-> temp.txt` :将结果输出到 temp.txt 文件)。
119131

120-
### 2.4 访问标志
132+
### 2.4 访问标志(Access Flags)
121133

122-
在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口,是否为 public 或者 abstract 类型,如果是类的话是否声明为 final 等等。
134+
在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口,是否为 `public` 或者 `abstract` 类型,如果是类的话是否声明为 `final` 等等。
123135

124136
类访问和属性修饰符:
125137

@@ -138,7 +150,7 @@ public class Employee {
138150

139151
![查看类的访问标志](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/查看类的访问标志.png)
140152

141-
### 2.5 当前类索引,父类索引与接口索引集合
153+
### 2.5 当前类(This Class)、父类(Super Class)、接口(Interfaces)索引集合
142154

143155
```java
144156
u2 this_class;//当前类
@@ -147,11 +159,11 @@ public class Employee {
147159
u2 interfaces[interfaces_count];//一个类可以实现多个接口
148160
```
149161

150-
**类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于 Java 语言的单继承,所以父类索引只有一个,除了 `java.lang.Object` 之外,所有的 java 类都有父类,因此除了 `java.lang.Object` 外,所有 Java 类的父类索引都不为 0。**
162+
类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于 Java 语言的单继承,所以父类索引只有一个,除了 `java.lang.Object` 之外,所有的 java 类都有父类,因此除了 `java.lang.Object` 外,所有 Java 类的父类索引都不为 0。
151163

152-
**接口索引集合用来描述这个类实现了那些接口,这些被实现的接口将按 `implements` (如果这个类本身是接口的话则是`extends`) 后的接口顺序从左到右排列在接口索引集合中。**
164+
接口索引集合用来描述这个类实现了那些接口,这些被实现的接口将按 `implements` (如果这个类本身是接口的话则是`extends`) 后的接口顺序从左到右排列在接口索引集合中。
153165

154-
### 2.6 字段表集合
166+
### 2.6 字段表集合(Fields)
155167

156168
```java
157169
u2 fields_count;//Class 文件的字段的个数
@@ -164,7 +176,7 @@ public class Employee {
164176

165177
![字段表的结构 ](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/字段表的结构.png)
166178

167-
- **access_flags:** 字段的作用域(`public` ,`private`,`protected`修饰符),是实例变量还是类变量(`static`修饰符),可否被序列化(transient 修饰符),可变性(final),可见性(volatile 修饰符,是否强制从主内存读写)。
179+
- **access_flags:** 字段的作用域(`public` ,`private`,`protected`修饰符),是实例变量还是类变量(`static`修饰符),可否被序列化(transient 修饰符),可变性(final),可见性(volatile 修饰符,是否强制从主内存读写)。
168180
- **name_index:** 对常量池的引用,表示的字段的名称;
169181
- **descriptor_index:** 对常量池的引用,表示字段和方法的描述符;
170182
- **attributes_count:** 一个字段还会拥有一些额外的属性,attributes_count 存放属性的个数;
@@ -176,7 +188,7 @@ public class Employee {
176188

177189
![字段的 access_flag 的取值](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/JVM/image-20201031084342859.png)
178190

179-
### 2.7 方法表集合
191+
### 2.7 方法表集合(Methods)
180192

181193
```java
182194
u2 methods_count;//Class 文件的方法的数量
@@ -185,7 +197,7 @@ public class Employee {
185197

186198
methods_count 表示方法的数量,而 method_info 表示方法表。
187199

188-
Class 文件存储格式中对方法的描述与对字段的描述几乎采用了完全一致的方式。方法表的结构如同字段表一样,依次包括了访问标志、名称索引、描述符索引、属性表集合几项。
200+
Class 文件存储格式中对方法的描述与对字段的描述几乎采用了完全一致的方式。方法表的结构如同字段表一样,依次包括了访问标志、名称索引、描述符索引、属性表集合几项。
189201

190202
**method_info(方法表的) 结构:**
191203

@@ -197,7 +209,7 @@ Class 文件存储格式中对方法的描述与对字段的描述几乎采用
197209

198210
注意:因为`volatile`修饰符和`transient`修饰符不可以修饰方法,所以方法表的访问标志中没有这两个对应的标志,但是增加了`synchronized``native``abstract`等关键字修饰方法,所以也就多了这些关键字对应的标志。
199211

200-
### 2.8 属性表集合
212+
### 2.8 属性表集合(Attributes)
201213

202214
```java
203215
u2 attributes_count;//此类的属性表中的属性数
@@ -211,4 +223,4 @@ Class 文件存储格式中对方法的描述与对字段的描述几乎采用
211223
- <https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html>
212224
- <https://coolshell.cn/articles/9229.html>
213225
- <https://blog.csdn.net/luanlouis/article/details/39960815>
214-
- 《实战 Java 虚拟机》
226+
- 《实战 Java 虚拟机》

0 commit comments

Comments
 (0)