String.intern() 将字符串引用登记到运行时常量池并返回该引用:先查池中是否存在内容相同的字符串,存在则返回其引用,否则将当前引用加入池中;JDK7+加入的是原对象引用,JDK6则复制内容;常用于去重和快速判等,但需避免对唯一字符串滥用。

String.intern() 的作用是将字符串对象“登记”到 JVM 运行时常量池中,并返回常量池中该字符串的引用。它不是简单地“复制一份放进去”,而是一套有明确规则的查找+注册机制。
intern 方法的核心逻辑
调用 str.intern() 时,JVM 会按以下步骤执行:
- 检查字符串常量池中是否已存在一个与当前字符串 内容完全相同(基于 equals) 的字符串引用;
- 如果存在,直接返回常量池中那个已有字符串的引用;
- 如果不存在,则将当前字符串对象的引用(注意:不是新创建副本)**加入常量池**,然后返回这个刚加入的引用。
关键点:JDK 7 及以后,常量池位于堆内存中,intern() 加入的是对象本身的引用,不是拷贝;JDK 6 中常量池在永久代,会把字符串内容复制一份再放入。
intern 与 new String("xxx") 的关系
常见误区是认为 new String("abc").intern() 会把堆上新对象“移进”常量池。实际上:
-
new String("abc")创建一个堆上的新 String 对象(内容为 "abc"),它和字面量"abc"指向不同对象; - 调用
.intern()后,由于常量池中已有字面量"abc"(编译期已加载),所以直接返回常量池中的引用,即等价于"abc"; - 若写
new String("xyz").intern(),且"xyz"之前未出现过,那么这次 intern 就会把该堆对象引用加入常量池并返回它。
判断 intern 是否生效的实用方式
最直接验证方法是用 == 比较引用:
-
"abc" == new String("abc").intern()→ true(因为字面量已存在); -
new String("def") == new String("def").intern()→ false(未 intern 前是堆对象,intern 后返回常量池引用,两者不同); -
new String("def").intern() == new String("def").intern()→ true(两次 intern 都返回常量池中同一个引用)。
intern 的实际用途和注意事项
主要适用于:大量重复字符串(如解析 JSON、读取 CSV 字段名)需减少内存占用,或需用 == 快速判等的场景。
- 不要无脑调用:每次 intern 都要查表(哈希查找),有性能开销;
- 避免对随机、唯一字符串 intern(如 UUID、时间戳拼接),会导致常量池膨胀甚至 OOM;
- 注意类加载顺序:若某字符串字面量尚未加载,首次 intern 它会成功注册;之后再出现同字面量,就会命中。
本质上,intern 是一种手动干预字符串引用归属的机制,用得好能省内存、提速度,用不好反而增加负担。

















