java中string内存分配核心是常量池与堆分工:字面量存常量池(jdk7起在堆中),new创建在堆,intern可将堆对象加入常量池,拼接则依是否含变量决定走池或堆。

Java中String对象的内存分配,核心在于常量池和堆内存的分工协作。理解这点,就能看懂==为什么有时true、有时false,也能避开重复创建对象带来的性能浪费。
字符串常量池:只存一份“相同内容”
常量池不是独立内存区域,而是堆内存中的一块特殊区域(JDK 7起已移入堆)。它负责管理编译期确定的字符串字面量,比如"hello"、"abc"这类直接用双引号写的值。
- 每次遇到字面量,JVM先查常量池里有没有完全相同的Unicode序列
- 有,就复用已有引用;没有,就新建一个并放入池中
- 所以
String a = "test"; String b = "test";中,a == b结果为true
new String():强制在堆中新建对象
使用new关键字创建String,不管常量池里是否存在相同内容,都会在堆中开辟新空间,生成一个全新的String实例。
- 例如
String x = new String("test");,会在堆中新建对象,同时确保常量池中有"test"(若无则加入) - 此时
x == "test"为false,因为一个是堆对象地址,一个是常量池引用 - 但
x.equals("test")仍为true,因为比较的是字符内容
intern():手动把堆对象“拉进”常量池
String.intern()是连接堆与常量池的桥梁。调用后,JVM会检查常量池是否有相同内容的字符串:
- 如果有,返回池中那个引用
- 如果没有,把当前字符串内容加入池,并返回该引用
- 因此
new String("test").intern() == "test"恒为true
拼接操作的内存行为
字符串拼接看似简单,但内存开销差异很大:
- 纯字面量拼接,如
"ab" + "c",编译期就优化成"abc",走常量池路径 - 含变量的拼接,如
"ab" + s,运行时通过StringBuilder完成,结果默认在堆中生成新String - 频繁拼接建议显式用
StringBuilder,避免反复创建临时对象
不复杂但容易忽略。关键就是记住:字面量走池,new走堆,intern可桥接,拼接看上下文。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











