字符串常量池是 JVM 为复用字符串字面量维护的池化结构:编译期出现的字面量会直接进入常量池,相同内容的字面量共享同一对象。JDK 7 之前常量池在永久代,JDK 7 起移入堆中,避免永久代空间不足的问题。
intern() 是 String 的 native 方法:调用时如果池中已有 equals 相等的字符串,返回池中的引用;否则把该字符串加入池中并返回池中引用(JDK 7 起,若对象已在堆中,池中只存引用而不再复制对象)。
经典陷阱:
String a = new String("abc"); // 创建两个对象:常量池 "abc" + 堆中新对象
String b = "abc";
System.out.println(a == b); // false
System.out.println(a.intern() == b); // true
String s1 = new String("he") + new String("llo");
s1.intern(); // 池中加入 s1 的引用
String s2 = "hello";
System.out.println(s1 == s2); // JDK 7+ 为 true
用途:大量重复字符串的场景(如解析、去重)用 intern 可省内存;但滥用会给常量池带来压力(它本质是固定大小的 StringTable,可用 -XX:StringTableSize 调整),过度 intern 反而拖累 GC。
追问方向:JDK 6 与 7 之后 intern 行为差异?G1 的字符串去重(-XX:+UseStringDeduplication)?
(约 360 字)