JVM Class中常量池 17 种 cp_info 表类型 浅谈

前置说明:本次讲解的17 种是 JVM 规范定义的「完整标准常量池表类型」 ,无删减无遗漏,所有 Java 版本(JDK8 及以上)完全通用,这 17 种也是constant_pool常量池数组中cp_info的全部取值类型。


✅ 一、常量池 & cp_info 【前置核心必知】(看不懂这个,后面全白学)

1. 常量池的本质

常量池是 Class 文件中最大、最核心、最复杂 的部分,存储 Class 运行所需的所有字面量 + 所有符号引用,是 JVM 解析类的核心数据源。

2. cp_info 统一结构(所有 17 种类型的共性)

常量池是一个不定长的表结构数组 ,数组中每一个元素都是一个 cp_info 结构,所有 17 种常量类型,都遵循这个统一的结构规范

bash 复制代码
cp_info {
    u1 tag;        // 【类型标记位】1字节,核心!值决定当前常量是哪一种类型
    u1 info[];     // 【不定长数据区】跟随tag,不同常量类型,这里的结构完全不同
}

✅ 核心规则:通过第一个字节 tag 的值,就能唯一确定当前常量的具体类型 ,比如 tag=1 → 字符串 UTF-8 常量,tag=7 → 类常量,这是 JVM 解析常量池的核心依据。

3. 常量池的基础规则(3 个高频考点)

① 常量池的索引从 1 开始,索引 0 是保留位,无任何实际意义;

② 常量池的容量 constant_pool_count 是「容量值」,实际元素个数 = constant_pool_count - 1

③ 17 种类型的tag值是连续无断层的(1~18,仅缺 15),对应刚好 17 种常量类型;

④ 常量池中的常量支持相互引用(最核心的特性),比如:字段引用常量 会引用 类常量 + 名称和类型常量,这是符号引用的核心逻辑。

4. 17 种常量类型【Tag 值速查表】(必备速记,建议收藏)

所有 17 种类型的tag标记值、标准名称一次性列全,按 tag 值升序排列,无任何遗漏,后面的详解完全对应这个列表:

tag 值 常量类型标准名称 中文简称 核心用途 高频度
1 CONSTANT_Utf8_info UTF-8 字符串常量 存储所有字符串内容(字面量) ✅✅✅最高频
2 CONSTANT_Integer_info 整型常量 存储 int 类型字面量 ✅高频
3 CONSTANT_Float_info 浮点型常量 存储 float 类型字面量 ✅高频
4 CONSTANT_Long_info 长整型常量 存储 long 类型字面量 ✅中频
5 CONSTANT_Double_info 双精度浮点常量 存储 double 类型字面量 ✅中频
6 CONSTANT_Class_info(旧) 废弃类型 JVM 规范保留,无实际用途 ❌无
7 CONSTANT_Class_info 类 / 接口常量 类、接口的符号引用 ✅✅✅最高频
8 CONSTANT_String_info 字符串常量 String 字面量的符号引用 ✅✅✅最高频
9 CONSTANT_Fieldref_info 字段引用常量 类的成员变量符号引用 ✅✅✅最高频
10 CONSTANT_Methodref_info 实例方法引用常量 类的实例方法符号引用 ✅✅✅最高频
11 CONSTANT_InterfaceMethodref_info 接口方法引用常量 接口的方法符号引用 ✅中频
12 CONSTANT_NameAndType_info 名称 + 类型常量 字段 / 方法的名称 + 类型描述符 ✅✅✅最高频
13 CONSTANT_MethodHandle_info 方法句柄常量 方法句柄的符号引用 (JDK7+) ✅低频
14 CONSTANT_MethodType_info 方法类型常量 方法的类型描述符 (JDK7+) ✅低频
15 预留 tag 值,未定义类型 ❌无
16 CONSTANT_InvokeDynamic_info 动态调用点常量 动态调用的核心常量 (JDK7+) ✅中频
17 CONSTANT_Dynamic_info 动态常量 动态计算常量的值 (JDK9+) ✅低频
18 CONSTANT_Module_info 模块常量 模块的符号引用 (JDK9+) ✅低频

重要说明:tag=6 的CONSTANT_Class_info是历史废弃类型,现代 JVM 中完全不用,所以有效标准类型共 17 种,对应 tag:1-5、7-14、16-18。


✅ 二、17 种常量池表类型【分大类 逐类详解】(按重要性排序,重点突出)

为了方便理解和记忆,我不会按 tag 值生硬排序,而是按「用途 + 重要性 」分为 5 大类别 讲解,高频必考的核心类型优先讲、详细讲,低频的新增类型简洁讲,兼顾「应试」和「实战」,这是最高效的学习方式。

✔️ 第一类:基础字面量常量(tag:1/2/3/4/5)【共 5 种,最基础,无引用】

核心特征:存储「直接的字面量数据」,不依赖其他常量,无任何符号引用,是常量池的「原子常量」 ,所有字符串、数值字面量都存在这一类里,tag=1 是重中之重,没有之一

1. CONSTANT_Utf8_info (tag=1) - 【王者级,最高频,必背】
  • 完整结构{u1 tag; u2 length; u1 bytes[length];}
  • 核心用途 :存储所有的字符串内容 ,包括:类名、接口名、字段名、方法名、字符串字面量、类型描述符(如Ljava/lang/String;)、注解值等,常量池中所有的文本信息,最终都存储在这个类型中
  • 关键细节 :采用 MUTF-8 编码 (JVM 自定义的 UTF-8 变种),不是标准 UTF-8;length是字符串的字节数,不是字符数。
  • 地位 :常量池的基石90% 的其他常量类型,都会引用这个类型,比如字符串常量、类常量,本质都是指向它的索引。
2. CONSTANT_Integer_info (tag=2)
  • 结构:{u1 tag; u4 bytes;}
  • 用途:存储int 类型的字面量 (4 字节有符号整数),比如代码中的int a=100;里的 100。
3. CONSTANT_Float_info (tag=3)
  • 结构:{u1 tag; u4 bytes;}
  • 用途:存储float 类型的字面量(4 字节单精度浮点)。
4. CONSTANT_Long_info (tag=4)
  • 结构:{u1 tag; u4 high_bytes; u4 low_bytes;}
  • 用途:存储long 类型的字面量(8 字节有符号长整型)。
  • ✅ 高频考点:占 2 个常量池索引位!因为 long 是 8 字节,JVM 规定:该常量的索引位 + 1 会被占用为「无效位」,比如该常量在索引 5,那么索引 6 不可用。
5. CONSTANT_Double_info (tag=5)
  • 结构:{u1 tag; u4 high_bytes; u4 low_bytes;}
  • 用途:存储double 类型的字面量(8 字节双精度浮点)。
  • ✅ 高频考点:和 long 一样,占 2 个常量池索引位,索引 + 1 为无效位。

✔️ 第二类:核心符号引用 - 基础引用型(tag:7/8)【共 2 种,次高频,单级引用】

核心特征:存储「符号引用」,不存储实际数据,只存储「指向其他常量的索引」 ,属于「单级引用常量」------ 只引用【第一类的字面量常量】,是连接字面量和复杂引用的桥梁,同样是必背高频考点

6. CONSTANT_Class_info (tag=7) - 【高频核心,必背】
  • 完整结构:{u1 tag; u2 name_index;}
  • 核心用途:存储类 / 接口的符号引用 ,比如:java/lang/Stringcom/test/Student 这些类的全限定名。
  • 关键细节:name_index指向常量池的索引 ,且这个索引一定指向 CONSTANT_Utf8_info(tag=1),因为类的全限定名是字符串,存储在 UTF-8 常量中。
  • 举例:如果 name_index=10,表示当前类的全限定名,是常量池第 10 个位置的 UTF-8 字符串常量的内容。
7. CONSTANT_String_info (tag=8) - 【高频核心,必背】
  • 完整结构:{u1 tag; u2 string_index;}
  • 核心用途:存储Java 字符串字面量的符号引用 ,对应代码中的String s="Java";里的"Java"
  • ✅ 顶级高频误区纠正:该常量不存储字符串内容! 真正的字符串内容在 CONSTANT_Utf8_info 中,string_index 是指向常量池的索引,且一定指向 tag=1 的 UTF-8 常量。
  • 补充:这就是「字符串常量池」的底层支撑,JVM 运行时会把该常量的引用解析为字符串常量池中的实际对象。

✔️ 第三类:核心符号引用 - 复合引用型(tag:9/10/11/12)【共 4 种,最高频,多级引用】

核心特征:常量池的核心灵魂,存储「字段、方法」的完整符号引用 ,属于「复合引用常量」------ 每个常量都由 2 个索引 组成,分别指向其他常量,形成「多级引用链」,这 4 种是面试最高频考点,必须倒背如流 ,也是 JVM 解析类的字段、方法的核心依据!前置铺垫:CONSTANT_NameAndType_info(tag=12) 是「字段 / 方法的元信息封装」,是这一类的基础,必须先讲它。

8. CONSTANT_NameAndType_info (tag=12) - 【顶级核心,必背】
  • 完整结构:{u1 tag; u2 name_index; u2 descriptor_index;}
  • 核心用途:存储字段 / 方法的「名称 + 类型描述符」,是字段、方法的核心元信息,所有字段 / 方法引用都依赖它。
  • 关键细节:① name_index:索引,指向 CONSTANT_Utf8_info(tag=1) → 存储字段名 / 方法名(如:agegetNamemain);② descriptor_index:索引,指向 CONSTANT_Utf8_info(tag=1) → 存储类型描述符 (JVM 的语法,比如I代表 int,Ljava/lang/String;代表 String,(Ljava/lang/String;)V代表无返回值、参数为 String 的方法)。
  • 举例:如果是字段private int age,则name_index指向 UTF-8 常量"age"descriptor_index指向 UTF-8 常量"I"
9. CONSTANT_Fieldref_info (tag=9) - 【顶级高频,必背】
  • 完整结构:{u1 tag; u2 class_index; u2 name_and_type_index;}
  • 核心用途:存储类的成员变量(字段)的完整符号引用 ,包括:实例字段(如user.name)、静态字段(如Math.PI),所有类的字段,都用这个常量描述
  • 引用规则【必背】:多级引用链,固定不可变✔️ class_index → 索引,必须指向 CONSTANT_Class_info(tag=7) → 表示这个字段属于哪个类;✔️ name_and_type_index → 索引,必须指向 CONSTANT_NameAndType_info(tag=12) → 表示这个字段的名称 + 类型。
  • 引用链总结:Fieldref → Class → Utf8(类名) + Fieldref → NameAndType → Utf8(字段名) + Utf8(类型)
10. CONSTANT_Methodref_info (tag=10) - 【顶级高频,必背】
  • 完整结构:{u1 tag; u2 class_index; u2 name_and_type_index;}
  • 核心用途:存储普通类的实例方法的完整符号引用 ,比如String.substring()User.getName()所有类的实例方法,都用这个常量描述
  • 引用规则【和 Fieldref 完全一致,必背】:✔️ class_index → 指向 CONSTANT_Class_info(tag=7) → 方法所属的类;✔️ name_and_type_index → 指向 CONSTANT_NameAndType_info(tag=12) → 方法的名称 + 参数 + 返回值。
  • 注意:不包含静态方法,静态方法也用这个常量(JVM 规范)。
11. CONSTANT_InterfaceMethodref_info (tag=11)
  • 完整结构:{u1 tag; u2 class_index; u2 name_and_type_index;}
  • 核心用途:存储接口的抽象方法的完整符号引用 ,比如List.add()Runnable.run()
  • 引用规则:和上面两个完全一致,唯一区别是class_index指向的一定是「接口的 Class 常量」。

✔️ 第四类:动态调用相关常量(tag:13/14/16)【共 3 种,JDK7 新增,Lambda 核心】

核心特征:JDK 1.7 为了支持「动态语言调用(invokedynamic 指令)」新增的 3 种常量类型 ,是 Java 8 Lambda 表达式、方法引用、动态代理的底层核心支撑,也是 JVM 的重要新特性,面试中属于「加分项考点」,必须知道用途和来源。

12. CONSTANT_MethodHandle_info (tag=13) - 方法句柄常量
  • 结构:{u1 tag; u1 reference_kind; u2 reference_index;}
  • 用途:存储方法句柄的符号引用,方法句柄是 JVM 的「方法指针」,可以指向任意方法(普通方法、静态方法、接口方法),是动态调用的核心。
  • 核心:reference_index 指向 字段 / 方法引用常量(tag9/10/11)。
13. CONSTANT_MethodType_info (tag=14) - 方法类型常量
  • 结构:{u1 tag; u2 descriptor_index;}
  • 用途:存储方法的类型描述符 ,本质是对方法的「参数 + 返回值」的封装,descriptor_index 指向 UTF-8 常量(方法的类型描述符字符串)。
14. CONSTANT_InvokeDynamic_info (tag=16) - 动态调用点常量
  • 结构:{u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index;}
  • 核心用途:动态调用的核心常量 ,支撑 JVM 的invokedynamic指令,是 Java 8 Lambda 表达式、Groovy 等动态语言的底层实现基础。
  • 特点:不再依赖固定的类 / 方法引用,而是通过「引导方法」动态计算出调用目标,实现真正的动态绑定。

✔️ 第五类:JDK9+ 新增扩展常量(tag:17/18)+ 废弃类型(tag:6)【共 3 种,低频】

核心说明:这部分是JVM 规范的扩展内容,tag=6 是历史废弃,tag=17/18 是 JDK9 为了支持「模块化系统 (Module)」新增的常量类型,日常开发 / 面试中极少考到,了解即可,不要求背诵,做到「有印象」就行。

15. CONSTANT_Class_info (tag=6) - 废弃常量
  • 用途:JVM 规范的历史保留位,早期版本的废弃类型,现代 JVM 中完全不使用,无任何实际意义,仅占一个 tag 值。
16. CONSTANT_Dynamic_info (tag=17) - JDK9 新增,动态常量
  • 核心用途:支持动态计算常量的值,可以在运行时通过引导方法动态生成常量,替代部分静态常量,增强灵活性。
17. CONSTANT_Module_info (tag=18) - JDK9 新增,模块常量
  • 核心用途:存储Java9 模块化系统 中的「模块名」符号引用,name_index 指向 UTF-8 常量(模块名),是 Java 模块化的底层支撑。

✅ 三、常量池【核心黄金规则】(5 条,吃透 = 掌握常量池本质,必考)

这 5 条规则是常量池的「底层逻辑」,所有 17 种类型的设计、使用都遵循这些规则,面试中但凡问到常量池,一定会围绕这些规则展开,优先级远高于背 17 种类型的结构!

规则 1:【引用为王】常量池的核心是「符号引用」,不是「存储数据」

除了第一类的字面量常量(tag1-5) 存储实际数据,剩下的 12 种全是「符号引用」 ------ 不存储实际内容,只存储「指向其他常量的索引」,JVM 运行时会把这些「符号引用」最终解析为内存中的「直接引用」(内存地址),这是 JVM 类加载的「解析阶段」核心工作。

规则 2:【多级引用链】复合常量的引用是「链式的、固定的」

所有复合引用常量(tag9/10/11)的引用关系是JVM 规范强制规定 的,不可改变,比如:CONSTANT_Fieldref_info → 必须指向 CONSTANT_Class_info + CONSTANT_NameAndType_info``CONSTANT_NameAndType_info → 必须指向 CONSTANT_Utf8_info + CONSTANT_Utf8_info这种「链式引用」最终都会溯源到 tag=1 的 UTF8 常量,这是常量池的「数据闭环」。

规则 3:【索引从 1 开始】永远的铁律,高频考点

常量池的索引绝对不会从 0 开始 ,索引 0 是「保留位」,表示「无引用」,比如:类的父类索引为 0,表示这个类是java/lang/Object(无父类)。

规则 4:【long/double 占两位】唯一的例外,必考

tag4 (long)、tag5 (double) 是常量池中唯一占用 2 个索引位的类型,因为它们是 8 字节数据,JVM 规定:这两个常量的「当前索引 + 1」会被标记为无效位,不可用。

举例:常量池索引 5 是 long 常量,那么索引 6 一定是无效位,下一个可用索引是 7。

规则 5:【UTF8 是基石】所有文本信息最终都在 tag1

CONSTANT_Utf8_info(tag=1) 是常量池的「基石中的基石」,没有它,其他所有常量都无法工作!所有的类名、方法名、字段名、字符串内容、类型描述符,最终都存储在这个类型中,其他常量只是指向它的索引。


✅ 四、高频必考「核心常量总结」

✅ 必背 8 种(按重要性排序):

  1. CONSTANT_Utf8_info (tag=1) - 所有字符串的存储地
  2. CONSTANT_Class_info (tag=7) - 类 / 接口的符号引用
  3. CONSTANT_NameAndType_info (tag=12) - 字段 / 方法的名称 + 类型
  4. CONSTANT_Fieldref_info (tag=9) - 字段的完整引用
  5. CONSTANT_Methodref_info (tag=10) - 方法的完整引用
  6. CONSTANT_String_info (tag=8) - 字符串字面量引用
  7. CONSTANT_Integer_info (tag=2) - 整型字面量
  8. CONSTANT_Float_info (tag=3) - 浮点型字面量

✅ 五、实操查看:如何看真实的常量池内容?(一行命令搞定)

理论看完,必须落地实操,用 JDK 自带的工具就能查看任意 Class 文件的常量池,看到真实的 17 种类型(实际中大部分是高频的 8 种),命令如下:

bash 复制代码
# 核心命令:反编译Class文件,查看完整的常量池+所有结构
javap -v 你的类名.class

示例:javap -v Student.class执行后,控制台会输出 Constant pool: 部分,里面就是该类的常量池,每行都是一个常量,格式如下:

bash 复制代码
Constant pool:
   #1 = Utf8               com/test/Student
   #2 = Class              #1             // com/test/Student
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               name
   #6 = Utf8               Ljava/lang/String;
   #7 = NameAndType        #5:#6          // name:Ljava/lang/String;
   #8 = Fieldref           #2:#7          // com/test/Student.name:Ljava/lang/String;

✅ 对应关系:#数字 是常量池的索引,后面的Utf8/Class/Fieldref就是我们讲的 17 种类型,完美对应!


✅ 最终总结

  1. JVM 常量池的cp_info17 种标准表类型 ,由tag值唯一标识,tag 范围:1-5、7-14、16-18;
  2. 17 种类型分 5 大类:字面量常量 (5)、基础引用常量 (2)、复合引用常量 (4)、动态调用常量 (3)、扩展常量 (3)
  3. 常量池的核心是「符号引用」,除了字面量,其余都是指向其他常量的索引,形成多级引用链;
  4. CONSTANT_Utf8_info(tag=1) 是基石,所有文本信息都存在这里;
  5. 高频必考 8 种类型,吃透即可应对所有面试 / 开发场景;
  6. 常量池索引从 1 开始,long/double 占 2 个索引位,是两大铁律。
相关推荐
不穿格子的程序员3 小时前
JVM篇1:java的内存结构 + 对象分配理解
java·jvm·虚拟机·内存结构·对象分配
一颗青果3 小时前
c++的异常机制
java·jvm·c++
萧曵 丶3 小时前
JVM 虚拟机类加载机制浅谈
jvm
chilavert3184 小时前
技术演进中的开发沉思-320 JVM:性能优化
jvm·性能优化
我是一只小青蛙88814 小时前
AVL树:平衡二叉搜索树原理与C++实战
java·jvm·面试
阿崽meitoufa16 小时前
JVM虚拟机:垃圾收集器和判断对象是否存活的算法
java·jvm·算法
杏花春雨江南1 天前
JavaWeb企业级项目实战:从SSH到SSM演进 + MQ/Redis/ES高可用架构落地全复盘(实战干货+避坑指南)
java·jvm·spring
期待のcode1 天前
性能监控工具
java·开发语言·jvm
小白不会Coding1 天前
一文详解JVM中类的生命周期
java·jvm·类的生命周期