Skip to content

Commit

Permalink
Class类文件结构-常量池
Browse files Browse the repository at this point in the history
  • Loading branch information
geekyspace committed Jul 22, 2024
1 parent 2dc536d commit 6d3c332
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/.vuepress/path/navbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default navbar([
text: "Java", icon: "java", children: [
{
text: "Java进阶-新版本特性", children:[
{text: "Java 8+ 版本特性体系", icon: "java", link: "md/java-features/"},
{text: "Java 8+版本特性体系", icon: "java", link: "md/java-features/"},
],
},
{
Expand Down
7 changes: 4 additions & 3 deletions src/.vuepress/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ table {
display: inline-table;
width: 100%;
border-radius: 1px;
margin: 0;

th {
text-align: left;
Expand All @@ -87,9 +88,9 @@ table {
}

// 去除“表格”的边框,看起来更加美观
//thead, tbody, tfoot, tr, td, th {
// border-width: 0 0 1px 0;
//}
thead, tbody, tfoot, tr, td, th {
border-width: 0 0 1px 0;
}
}

// 视觉优化 “夜间模式”
Expand Down
111 changes: 96 additions & 15 deletions src/md/jvm/basics/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ ClassFile {
u2 minor_version; // 次版本号
u2 major_version; // 主版本号
u2 constant_pool_count; // 常量池计数
cp_info constant_pool[constant_pool_count - 1]; // 常量池
cp_info constant_pool[constant_pool_count-1]; // 常量池
u2 access_flags; // 访问标志
u2 this_class; // 当前类索引
u2 super_class; // 父类索引
Expand All @@ -63,7 +63,7 @@ ClassFile {

![ClassFile 内容分析](https://img.geekyspace.cn/pictures/2024/202407220149546.png)

### 魔数(Magic Number)
### 魔数

魔数是头4个字节的值`0xCAFEBABE`,用于验证文件是否为有效的Class文件。
不仅限于Class文件,很多文件格式如`GIF``JPEG`等也使用魔数来进行身份识别。
Expand All @@ -75,29 +75,110 @@ ClassFile {
Java开发小组关键成员Patrick Naughton提到,他们选择这个值是因为它好玩且容易记忆,
象征着著名咖啡品牌Peet’s Coffee深受欢迎的Baristas咖啡,也预示着日后“Java”这一商标名称的出现。

### Class文件版本号(Minor&Major Version)
### Class文件版本号

紧跟魔数`0xCAFEBABE`之后的4个字节存储的是Class文件的版本号,其中:

* 第5~6字节:次版本号(Minor Version)
* 第7~8字节:主版本号(Major Version),Java 8 = 52.0

Java的主版本号从JDK 1.0的45开始,每次大版本发布都会+1
Java的主版本号从JDK 1.0的45开始,每次大版本发布都会+1
次版本号通常保持为0,对应一些次要的特性改进或修复。
以下是一些JDK版本及其对应的Class文件主版本号:

| JDK 版本 | 主版本号(10 进制) | 主版本号(16 进制) |
|---------|-------------|-------------|
| JDK 1.0 | 45 | 0x2D |
| JDK 6 | 50 | 0x32 |
| JDK 7 | 51 | 0x33 |
| JDK 8 | 52 | 0x34 |
| JDK 11 | 55 | 0x37 |
| JDK 17 | 61 | 0x3D |
| JDK 21 | 65 | 0x41 |

**Java版本对应表:**

| JDK版本 | 十进制 | 十六进制 | 发布时间 |
|--------|-----|------|------------|
| JDK1.1 | 45 | 0x2D | 1996-05-15 |
| JDK1.2 | 46 | 0x2E | 1998-12-08 |
| JDK1.3 | 47 | 0x2F | 2000-05-08 |
| JDK1.4 | 48 | 0x30 | 2002-02-13 |
| JDK1.5 | 49 | 0x31 | 2004-09-30 |
| JDK1.6 | 50 | 0x32 | 2006-12-11 |
| JDK1.7 | 51 | 0x33 | 2011-07-28 |
| JDK1.8 | 52 | 0x34 | 2014-03-18 |
| Java9 | 53 | 0x35 | 2017-09-21 |
| Java10 | 54 | 0x36 | 2018-03-20 |
| Java11 | 55 | 0x37 | 2018-09-25 |
| Java12 | 56 | 0x38 | 2019-03-19 |
| Java13 | 57 | 0x39 | 2019-09-17 |
| Java14 | 58 | 0x3A | 2020-03-17 |
| Java15 | 59 | 0x3B | 2020-09-15 |
| Java16 | 60 | 0x3C | 2021-03-16 |
| Java17 | 61 | 0x3D | 2021-09-14 |
| Java18 | 62 | 0x3E | 2022-03-22 |
| Java19 | 63 | 0x3F | 2022-09-20 |
| Java20 | 64 | 0x40 | 2023-03-21 |
| Java21 | 65 | 0x41 | 2023-09-19 |
| Java22 | 66 | 0x42 | 2024-03-19 |

### 常量池

常量池入口紧随主、次版本号之后,可以理解成Class文件的资源仓库。
与其他数据关联最多,占用空间最大,也是第一个出现的表类型数据项`cp_info`

**1、常量池计数**

由于常量项不固定,入口处`u2`类型的数据值表示**常量池计数**`constant_pool_count`)。

* 常量池的计数从1开始,即:`常量项 = 常量池计数 - 1`
* Class文件格式规范刻意将第0项常量空出,索引值0表示“不引用任何常量池项”

**2、常量类型**

常量池主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)

* **字面量:** 比较接近于Java语言层面的常量概念,如数值、文本字符串、final常量等
* **符号引用:** 符号引用则属于编译原理方面的概念,包括以下几类常量:
* 被模块导出或者开放的包(Package)
* 类和接口的全限定名(Fully Qualified Name)
* 字段的名称和描述符(Descriptor)
* 方法的名称和描述符
* 方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
* 动态调用点和动态常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)

不同于C/C++编译时有“连接”步骤,JVM在加载Class文件时才进行“动态连接”。
因此,Class文件不保存方法、字段最终在内存中的布局信息。
JVM在类加载时从常量池获取符号引用,并在类创建或运行时解析为具体地址。

**3、常量表结构**

[JVM虚拟机规范第四章-常量池](https://docs.oracle.com/javase/specs/jvms/se22/html/jvms-4.html#jvms-4.4)
定义了`constant_pool`表条目具有以下通用格式:

```java
cp_info {
u1 tag;
u1 info[];
}
```

常量池中的每项常量都是一个表,起始的第一位是一个`u1`类型的标志位(tag),表示当前常量的类型。

1. 最初设计的11种常量类型
2. 为支持动态语言,增加了4种动态语言相关的常量
3. 为支持Java模块化系统(Jigsaw),新增了`CONSTANT_Module_info``CONSTANT_Package_info`

| 类型 | 标志(tag) | 描述 |
|----------------------------------|---------|-----------------|
| CONSTANT_Utf8_info | 1 | UTF-8编码的字符串 |
| CONSTANT_Integer_info | 3 | 整型字面量 |
| CONSTANT_Float_info | 4 | 浮点型字面量 |
| CONSTANT_Long_info | 5 | 长整型字面量 |
| CONSTANT_Double_info | 6 | 双精度浮点型字面量 |
| CONSTANT_Class_info | 7 | 类或接口的符号引用 |
| CONSTANT_String_info | 8 | 字符串类型字面量 |
| CONSTANT_Fieldref_info | 9 | 字段的符号引用 |
| CONSTANT_Methodref_info | 10 | 类中方法的符号引用 |
| CONSTANT_InterfaceMethodref_info | 11 | 接口中方法的符号引用 |
| CONSTANT_NameAndType_info | 12 | 字段或方法的部分符号引用 |
| CONSTANT_MethodHandle_info | 15 | 表示方法句柄 |
| CONSTANT_MethodType_info | 16 | 表示方法类型 |
| CONSTANT_Dynamic_info | 17 | 表示一个动态计算常量 |
| CONSTANT_InvokeDynamic_info | 18 | 表示一个动态方法调用点 |
| CONSTANT_Module_info | 19 | 表示一个模块 |
| CONSTANT_Package_info | 20 | 表示一个模块中开放或者导出的包 |

### 访问标志

### 类索引、父类索引与接口索引集合
Expand Down

0 comments on commit 6d3c332

Please sign in to comment.