string内存分配由创建方式决定:字面量优先复用常量池,new强制堆中新建,拼接依编译期/运行期路径不同,intern可手动将堆字符串加入常量池。

Java 中 String 的内存分配不是随机的,而是由创建方式决定它落在哪——常量池还是堆。关键不在“怎么写”,而在“JVM 看到这行代码时做了什么”。
字面量赋值:优先查池、复用为主
写 String s = "hello"; 时,JVM 会立即去字符串常量池里找有没有内容完全相同的字符串(按 Unicode 序列比对):
- 有 → 直接返回池中已有对象的引用,不新建任何对象
- 没有 → 在常量池中创建一份,再返回该引用
所以 String a = "abc"; String b = "abc"; 中,a 和 b 指向同一块内存,a == b 为 true。常量池在 JDK 7 起已移入堆内存,但它仍是逻辑独立的“只存一份”的区域。
new 创建:强制堆中新开辟
写 String s = new String("hello"); 时,动作分两步:
- 先确保常量池中有 "hello"(若无则加入)
- 再在堆中新建一个 String 对象,其内部 value 字段指向常量池中的字符数据,但对象本身是全新实例
因此即使内容相同,new 出来的对象和字面量引用地址永远不同,s == "hello" 恒为 false;但 s.equals("hello") 仍为 true,因为比较的是字符内容。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
拼接行为:编译期 vs 运行期路径不同
字符串拼接看似统一,实际内存路径差异很大:
- "ab" + "c":纯字面量,编译器直接优化成 "abc",走常量池
- "ab" + s(s 是变量):运行时通过 StringBuilder 完成,结果默认生成在堆中
- 频繁拼接建议显式使用 StringBuilder.append(),避免每次拼接都新建临时对象
intern():手动打通堆与池的桥
String.intern() 是唯一能将堆中字符串“登记”进常量池的方法:
- 调用时,JVM 查常量池是否有相同内容
- 有 → 返回池中引用
- 没有 → 把当前字符串内容加入池,再返回该引用
所以 new String("test").intern() == "test" 一定为 true。适合用在动态生成(如读取配置、数据库字段)后需长期复用的场景。
不复杂但容易忽略。核心就四句话:字面量走池,new 走堆,intern 可桥接,拼接看上下文。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










