intern() 方法将堆中字符串引用加入字符串常量池,若内容已存在则返回池中引用,否则加入并返回该引用;jdk 7+ 常量池位于堆内存,支持 == 判等且线程安全。

Java 中的 intern() 方法可以将堆中创建的字符串对象手动加入字符串常量池(String Pool),前提是该字符串内容在常量池中尚不存在。 它不会“强制覆盖”或“重复添加”,而是返回常量池中已存在(或新加入)的字符串引用。理解它的行为,关键在于区分“字符串内容”和“对象引用”,以及 JVM 对字符串常量池的管理机制。
intern() 的核心逻辑
调用 str.intern() 时:
- JVM 检查字符串常量池中是否已有**内容完全相同**的字符串(基于
equals()判断); - 如果存在,直接返回常量池中那个字符串对象的引用;
- 如果不存在,就把当前字符串对象的引用(注意:不是拷贝内容,而是引用本身)放入常量池,并返回该引用。
⚠️ 注意:从 JDK 7 起,字符串常量池已从永久代(PermGen)移到堆内存(Heap),intern() 操作的是堆中的这个池,且对已存在的字符串会复用其引用,不创建新对象。
常见使用场景与示例
适用于动态拼接、IO 读取、JSON 解析等产生的字符串,希望复用以节省内存或支持 == 判等:
-
拼接后入池:
String s1 = new String("a") + new String("b"); // 堆中新建 "ab"<br> String s2 = s1.intern(); // 若常量池无 "ab",则加入并返回它;s2 指向常量池中的 "ab"<br> String s3 = "ab"; // 字面量,直接指向常量池中的 "ab"<br> System.out.println(s2 == s3); // true(JDK 7+) -
避免重复创建相同内容的字符串:
比如解析大量日志行得到的 status 字段(如 "SUCCESS", "FAILED"),可统一调用status.intern(),后续用 == 比较更高效。
注意事项与陷阱
- 不是所有字符串都适合 intern:频繁调用或对长/唯一字符串(如 UUID、时间戳)调用,会导致常量池膨胀,反而增加 GC 压力;
-
== 判等仅在双方都经过 intern 或一方为字面量时才可靠:
new String("hello").intern() == "hello"是 true;但new String("hello") == "hello"是 false; - intern() 返回的是常量池引用,原对象仍存在堆中(除非无其他引用被回收);
- 多线程下
intern()是线程安全的,JVM 内部已同步处理。
如何验证是否成功入池?
最直接方式是用 == 与对应字面量比较:
- 先确保常量池中原本没有该字符串(例如用
new String("test").intern()后再用"test"); - 若
str.intern() == "test"返回 true,说明已成功关联到常量池; - 也可借助 JMX 或 JVM 参数(如
-XX:+PrintStringTableStatistics)观察池大小变化(生产慎用)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











