String.intern() 的核心是查找字符串常量池并复用引用,不创建新对象;JDK 7+ 将 StringTable 移至堆中,存储对堆对象的引用,未命中时直接存入原对象引用。

String.intern() 的底层逻辑,核心在于 JVM 对字符串常量池(String Table)的管理机制,它不是简单“复制一份进池子”,而是执行一次**池中查找 + 有条件引用替换**的过程。
常量池本质是哈希表,intern 是查表并可能更新引用
JDK 7 及以后,运行时常量池中的字符串表(String Table)是一个基于哈希的结构(StringTable),内部维护着对堆中字符串对象的弱引用(JDK 7+)或直接引用(JDK 6 及以前)。调用 intern() 时:
- 先按当前字符串的
hashCode和equals规则,在 StringTable 中查找是否已有内容相同的字符串引用; - 如果找到,直接返回池中已存在的那个字符串对象的引用;
- 如果没找到,就把当前字符串对象的引用(注意:不是新拷贝,是原对象地址)存入 StringTable,并返回该引用。
关键点:intern 不创建新对象,只建立/复用池中引用
很多人误以为 intern() 会把字符串“复制”到方法区(元空间),其实它操作的是引用关系:
- 堆中原本的字符串对象不会被移动或复制;
- StringTable 存储的是指向堆中字符串对象的引用(JDK 7+);
- 所以
s.intern() == s是否成立,取决于s是否已是池中唯一引用——比如通过字面量创建的字符串天然在池中,而new String("abc")创建的对象在堆中独立存在,其intern()调用后返回的是字面量 "abc" 的引用,而非自身。
不同 JDK 版本差异影响行为表现
底层实现细节随 JDK 演进而变化,直接影响 intern() 的效果:
-
JDK 6:常量池在永久代(PermGen),
intern()若未命中,会把字符串内容复制一份到永久代,返回新副本地址;此时new String("abc").intern() == "abc"为 true,但和原new对象不等。 -
JDK 7+:常量池移至堆(后为元空间,但 StringTable 仍在堆),
intern()若未命中,直接将堆中该字符串对象的引用存入 StringTable;因此只要对象已在堆中,intern()返回的就是它自己(前提是池中无重复)。
触发 intern 的实际意义在于去重与节省内存
手动调用 intern() 主要用于明确控制字符串生命周期和引用一致性,常见于:
- 大量重复字符串(如解析 JSON、CSV 中的字段名、状态码);
- 需用
==高效判断相等性的场景(避免频繁调用equals); - 配合
WeakHashMap或字符串缓存做键值管理时,确保键的唯一性。

















