string.intern() 是池查找+条件绑定操作:查池中是否存在内容相同的字符串,有则返回池中引用,无则将当前对象引用登记入池并返回;jdk7+后池在堆中,不复制对象。

String.intern() 方法确实可以将堆中已存在的字符串对象“登记”到字符串常量池(JVM 1.7+ 后池位于堆内存中),但它**不是“强行放入”或“复制入池”**,而是执行一次**池查找 + 条件性绑定**的操作。理解这一点,才能正确使用它。
intern 的真实行为:查池、有则返、无则绑
调用 str.intern() 时,JVM 会:
- 检查字符串常量池中是否已存在一个 内容完全相同(基于
equals())的字符串对象; - 如果存在,直接返回池中那个字符串的引用;
- 如果不存在,就把当前字符串对象的引用(不是新拷贝!)存入池中,并返回该引用。
注意:JDK 7 及以后,字符串常量池被移到了堆内存中,所以“入池”本质上是把堆中某个字符串对象的引用记录进池的哈希表里,不涉及对象迁移或复制。
典型用法:消除重复字符串,节省内存
当你从数据库、文件或网络读取大量重复文本(如状态码、城市名、配置键)时,可主动 intern:
String city = resultSet.getString("city"); // 堆中新建的字符串
city = city.intern(); // 若池中已有"Beijing",就复用它;否则把当前city引用记入池
后续所有相同内容的字符串调用 intern() 后都会指向同一个对象,== 比较即可判等,比 .equals() 更快,也减少堆内存占用。
重要限制与陷阱
- 不能保证“一定新建”或“强制覆盖”:intern 不会删除池中原有对象,也不会替换。池中已有 "hello",再对另一个 "hello"(堆中不同对象)调用 intern,只会返回池里的那个。
-
对字面量无效:
"abc".intern() == "abc"恒为 true,因为字面量本身就在池中,intern 直接返回自己。 - 性能开销:intern 是 native 方法,涉及哈希查找和可能的锁(尤其高并发下),不要滥用在高频短生命周期字符串上。
-
无法 intern null 或非 String 对象:传 null 会抛
NullPointerException。
验证是否成功入池的小技巧
用 == 比较 intern 结果与对应字面量:
String s1 = new String("world"); // 堆中新建
String s2 = s1.intern();
System.out.println(s2 == "world"); // true → 说明 s1 已“绑定”到池中 "world"
这个 true 就证明 intern 生效了:堆中 s1 的引用已被登记进池,并被 s2 拿到。











