string.intern() 方法检查常量池中是否存在内容相同的字符串引用,存在则返回池中引用,否则将当前字符串引用加入池并返回;jdk 7+ 后常量池位于堆中,存的是对象引用而非副本,需谨慎使用以防内存膨胀和性能开销。

Java 中的 String.intern() 方法并不是“将字符串放入常量池”,而是**检查常量池中是否存在与当前字符串内容相同的字符串对象;如果存在,就返回池中的那个引用;如果不存在,就把该字符串的引用(注意:不是拷贝内容)加入常量池,并返回这个引用**。
intern 的核心逻辑是查表 + 引用登记
常量池里存的不是字符串值本身,而是对 String 对象的引用(JDK 7+ 后常量池在堆中)。调用 intern() 时:
- JVM 会按字符内容(Unicode 编码序列)计算哈希,在字符串常量池中查找是否已有相同内容的
String实例引用 - 若找到,直接返回该引用
- 若没找到,就把当前字符串对象的引用添加到池中,再返回它
new String("abc").intern() 的行为容易误解
比如:
String s1 = new String("abc"); // 在堆上新建对象
String s2 = s1.intern(); // 检查常量池:字面量 "abc" 已存在(编译期入池),所以返回池中那个引用
String s3 = "abc"; // 直接指向常量池中的实例
此时 s2 == s3 为 true,但 s1 == s2 是 false(因为 s1 是堆中新对象)。intern() 并没有“把 s1 放进去”,而是发现已有 "abc" 就复用了。
真正新增进常量池的情况
只有当字符串内容在常量池中完全不存在时,intern() 才会登记当前对象引用。例如:
String s1 = new StringBuilder().append("ab").append("c").toString(); // 动态拼接,不在池中
String s2 = s1.intern(); // 此时才把 s1 的引用加入常量池
String s3 = "abc"; // 这个还是编译期已存在的字面量,和 s2 指向同一个对象(JDK 7+)
注意:从 JDK 7 开始,常量池移到堆内存,所以 intern() 登记的是堆中对象的引用,不是复制一份新字符串。
使用 intern 要小心内存和性能
频繁调用 intern() 可能导致常量池膨胀(尤其处理大量唯一字符串时),且哈希查找有开销。除非明确需要字符串引用相等(如做 key 查表、避免重复对象),否则不建议滥用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











