Java字符串字面量在编译期自动放入堆中的字符串常量池(JDK7+),如"hello";new String("hello")在堆中新建对象,需intern()才指向池中实例。

Java 中字符串字面量(如 "hello")在编译期确定,会被自动放入字符串常量池(String Constant Pool),该池位于堆内存中(JDK 7+),而非方法区或永久代。
字符串常量池的位置变迁
早期 JDK(6 及以前):常量池在永久代(PermGen),属于方法区的一部分;
JDK 7:常量池被移到堆内存(Heap)中,与普通对象一样受 GC 管理;
JDK 8+:永久代被元空间(Metaspace)取代,但字符串常量池仍在堆里。
字符串字面量一定在常量池中
所有双引号直接写的字符串(如 "abc"、""、"123")在类加载的“解析阶段”就会被检查并放入常量池(若尚不存在)。这个过程由 JVM 自动完成,无需 new 或 intern()。
- 同一字面量多次出现,只创建一个对象,所有引用都指向池中同一个实例
- 例如:
String a = "test"; String b = "test";→a == b为 true - 字面量拼接(纯编译期可确定的)也进入常量池:
"a" + "b"等价于"ab"
new String() 创建的对象不在常量池(除非显式 intern)
new String("hello") 会做两件事:
① 检查常量池中是否有 "hello",没有则加入;
② 在堆中新建一个 String 对象,内容与池中相同,但地址不同。
立即学习“Java免费学习笔记(深入)”;
- 所以
new String("hello") == "hello"是 false(引用不同) - 但
new String("hello").equals("hello")是 true(内容相同) - 调用
.intern()后,返回的是常量池中的引用:new String("hello").intern() == "hello"为 true
运行期拼接通常不入常量池
含变量的字符串拼接(如 "a" + s、s1 + s2)在运行期通过 StringBuilder 完成,结果是堆中新对象,不会自动进常量池。
-
String s1 = "a"; String s2 = "b"; String s3 = s1 + s2;→s3是堆对象,s3 == "ab"为 false - 若需入池,需显式调用
s3.intern() - 例外:编译器能完全确定的常量表达式(如
final String s = "a"; String t = s + "b";)仍可能优化进池
理解常量池位置和字面量的自动驻留机制,有助于分析字符串比较、内存占用及 intern 的使用场景。关键记住:字面量天生入池,new 出来的是堆对象,池在堆里,不是“特殊区域”。









