运行时常量池是class文件常量池的内存映射,不负责字符串动态入池;字符串驻留由JVM级StringTable管理,intern()是唯一运行时入池操作。

类加载过程中,运行时常量池(Runtime Constant Pool)本身不执行字符串的“动态入池”,它只是 class 文件常量池在 JVM 内存中的映射结构;真正负责字符串驻留的是独立的字符串常量池(StringTable),而 String.intern() 是唯一能在运行时触发字符串入池的操作。
运行时常量池 ≠ 字符串常量池
运行时常量池是每个类或接口在加载时,由 class 文件常量池内容“复制”并解析后生成的内存结构,位于堆中(JDK 7+)。它存储的是符号引用(如类名、方法名、字段名等)解析后的直接引用,也包括字符串字面量的引用。但它本身不管理字符串对象的复用——这个职责交给了全局唯一的 字符串常量池(StringTable),它是 JVM 级别的哈希表,专用于字符串驻留。
字符串字面量入池发生在类加载解析阶段
当你写 String s = "hello";,编译器把 "hello" 收进 class 文件常量池。JVM 在类加载的解析阶段(resolve phase),遇到 ldc 指令时会:
- 计算该字面量的哈希值,定位到 StringTable 对应桶位
- 遍历桶内链表/红黑树,逐个用
equals()比较内容(不是仅靠哈希) - 命中则复用已有引用;未命中则在堆中新建 String 实例,并将该实例引用存入 StringTable
这个过程是批量、一次性、静态完成的,与程序运行逻辑无关,不属于“运行时动态”行为。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
intern() 是唯一真正的运行时入池入口
只有通过显式调用 .intern(),才能在程序运行中把堆上新创建的字符串(如 new String("hello") 或拼接结果)尝试加入字符串常量池:
- JDK 7+:先查 StringTable,存在则返回已有引用;不存在则把当前堆中对象的引用存入 StringTable 并返回
- 不会复制字符串内容,也不改变原对象,只是建立或复用一个指向堆中 String 实例的引用
- 返回值与常量池中已有字符串比较时,
==成立(引用相同),而不仅仅是equals()为 true
常见误区澄清
以下说法不准确:
- “运行时常量池负责字符串动态入池” → 实际由 StringTable 承担
- “字符串字面量是运行时才入池” → 它在类加载解析阶段就已完成
- “intern() 把字符串复制进常量池” → JDK 7+ 只存引用,对象仍在堆中
- “所有 new 出来的字符串调用 intern() 都会新增条目” → 若内容已存在,则直接返回旧引用,无新增

















