java字符串拼接本质是创建新对象,常量拼接编译期优化入常量池,含变量拼接运行期用stringbuilder在堆中生成新string,intern()可手动登记堆字符串到常量池,循环拼接应显式复用stringbuilder避免性能损耗。

Java 中 String 拼接看似简单,实际背后涉及编译优化、内存分配和对象创建机制。它不是“修改”原字符串,而是生成新对象——这是由 String 的不可变性决定的。
常量拼接:编译期优化,结果进字符串常量池
当所有操作数都是字面量或 final 修饰的字符串变量时(如 "a" + "b" + "c" 或 final String s = "a"; String t = s + "b";),JVM 在编译阶段就完成拼接,生成的字符串直接存入字符串常量池。
- 字节码中不会出现
StringBuilder相关指令,而是直接加载常量(ldc) - 多个相同拼接结果会复用同一个常量池地址,所以
==比较返回true - 这种写法高效安全,适合固定内容组合
含变量拼接:运行期创建 StringBuilder,结果在堆中
只要参与拼接的任意一方是普通变量(非 final 字面量),拼接就在运行时进行,JVM 自动使用 StringBuilder 完成操作。
- 等价于:
new StringBuilder().append(s1).append(s2).toString() - 每次拼接都新建
StringBuilder对象(默认初始容量 16),再转成新的String实例,原字符串不受影响 - 结果对象位于堆内存,不自动进常量池,即使内容相同,
==也返回false
intern():手动将堆中字符串“登记”进常量池
String.intern() 是一个显式干预常量池的手段,用于复用已有字符串引用。
- JDK7+ 后,
intern()不复制对象,而是把堆中字符串的引用存入常量池 - 调用后若池中已存在相同内容字符串,就返回池中引用;否则登记当前引用并返回
- 可用来减少重复字符串内存占用,但要注意:频繁调用可能引发哈希冲突,影响性能
性能与写法建议:别让 + 在循环里“反复造轮子”
单次拼接用 + 完全没问题,JDK9 起还通过 StringConcatFactory 动态生成高效字节码。但循环内滥用会导致严重性能问题。
- 反例:
result += str在 for 循环中 —— 每次迭代都 new 一个StringBuilder,再丢弃,产生大量临时对象 - 正例:显式用
StringBuilder复用实例,提前预估容量(如new StringBuilder(1024))避免多次扩容 - 多线程场景下,优先选
ThreadLocal<stringbuilder></stringbuilder>,而非同步开销大的StringBuffer
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











