string.intern()方法用于将字符串对象在运行时常量池中查找或登记等价字符串并返回池中引用;jdk 7+常量池位于堆内存,intern后原堆对象仍存在,返回值必为池中引用,但无法直接增删查改池内容。

String.intern() 方法不是用来“手动操作”字符串常量池的工具,而是让一个字符串对象尝试在运行时常量池中查找等价字符串;若存在则返回池中引用,否则将该字符串(或其副本)加入池并返回其引用。它不提供直接增删查改常量池的能力,也不暴露池的内部结构。
intern() 的实际行为与语义
调用 intern() 时,JVM 会检查字符串常量池中是否已存在内容相同的字符串(通过 equals() 判断)。如果存在,直接返回池中已有字符串的引用;如果不存在,则将当前字符串对象(或其内容的一个新实例)放入常量池,并返回该池中字符串的引用。
- JDK 7 及以后,常量池位于堆内存中(而非永久代),因此 intern 后的对象可被 GC 回收(当无引用时)
- intern() 返回的一定是常量池中的对象,但原字符串对象仍存在于堆中(除非被丢弃)
- 两个通过字面量创建的相同字符串(如
"abc")天然在常量池中,且引用相同
常见误用与对比示例
理解 intern() 关键在于区分“字符串内容相等”和“引用相等”。以下代码揭示典型误区:
String s1 = new String("hello"); // 堆中新对象
String s2 = "hello"; // 常量池中已有
String s3 = s1.intern(); // 返回常量池中 "hello" 引用
System.out.println(s1 == s2); // false(堆对象 vs 池对象)
System.out.println(s2 == s3); // true(都指向池中同一实例)
System.out.println(s1.equals(s2)); // true(内容相同)
注意:s1.intern() 并不会“修改”s1 本身,只是返回池中对应引用;s1 仍是堆中独立对象。
何时适合使用 intern()
intern() 主要用于节省内存或加速字符串比较,但需谨慎评估开销与收益:
- 大量重复短字符串(如解析日志中的状态码、协议关键字)且生命周期较长时,可减少堆内存占用
- 后续需频繁用
==做快速判等(如 switch 字符串、枚举模拟),且能保证所有输入都经过 intern - 避免在不可控输入(如用户上传的长文本)上调用 intern,可能引发内存泄漏或性能下降
无法真正“手动操作”常量池
Java 不提供 API 直接遍历、清空或删除常量池中的条目。intern() 是唯一与常量池交互的公开方法,且其行为由 JVM 实现决定(如是否复用原对象、何时回收等)。反射或 Unsafe 操作不仅不安全、不可移植,且在现代 JDK(尤其是模块化后)已被严格限制或彻底移除。
试图绕过规范操作常量池,往往导致不可靠、难维护、易出错的代码。应优先考虑设计层面的优化(如使用枚举、缓存 Map 或 flyweight 模式),而非依赖 intern() 做“手动管理”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











