java字符串拼接分编译期常量折叠和运行期stringbuilder构建两种机制:字面量拼接如"a"+"b"在编译时直接生成"ab"存入常量池;含变量则编译为stringbuilder.append链式调用,循环中滥用+=会导致性能劣化。

Java 中字符串拼接不是“把两个字符串连起来”那么简单,它背后牵扯到内存分配、对象创建、编译优化和运行时策略。理解底层原理,才能避开性能雷区。
常量拼接:编译期就搞定,不占运行时资源
当所有参与拼接的都是字面量(如 "a" + "b" + "c"),JDK 在编译阶段就会完成合并,生成一个常量字符串 "abc",直接存入字符串常量池。运行时不会创建任何新对象,也不会调用 StringBuilder。
- 这种写法高效安全,适合配置项、SQL 模板等固定内容
- 注意:只要有一个是变量(哪怕只是 final String x = "a"; x + "b"),就不再算“纯常量拼接”,会退回到运行时处理
变量参与拼接:默认走 StringBuilder,但有隐藏开销
只要拼接表达式中含变量(如 s1 + s2 或 "Hi, " + name),编译器会自动翻译成 StringBuilder 调用。例如:
源码:String result = a + b + c;
等效编译后代码:new StringBuilder().append(a).append(b).append(c).toString();
- 单次拼接没问题,JVM 会复用 StringBuilder 实例(JDK9+ 还进一步优化为动态调用)
- 但循环内写 result += i 是大忌——每次都会新建 StringBuilder,再 toString(),导致 O(n²) 时间复杂度和大量临时对象
- 正确做法是显式复用 StringBuilder,预设容量(如
new StringBuilder(1024))可避免频繁扩容
不可变性不是限制,而是设计选择
String 的“不可变”指对象内容无法修改,而非不能赋值。每次 + 拼接,本质是创建新对象,原字符串毫发无损。
- 底层存储从 JDK8 的
char[]升级为 JDK9+ 的byte[] + coder,对纯 ASCII 字符节省近一半内存 - 不可变带来线程安全、哈希缓存稳定、常量池复用三大优势,是高性能场景的基础保障
- 别试图用反射修改 String 内容——破坏设计契约,可能引发 JVM 层面异常或安全机制拦截
选型关键:看场景,不迷信语法糖
拼接方式没有绝对优劣,只有是否匹配上下文:
- 模板化少量拼接(如日志前缀):用 + 简洁清晰,JDK 自动优化到位
- 高频动态拼接(如 XML/JSON 构建、批量 SQL 拼装):必须用 StringBuilder,并考虑预分配容量
- 多线程共享拼接(极少见):优先用 ThreadLocal
,比 StringBuffer 更轻量;高并发且 JDK14+ 可评估 ConcurrentStringBuilder - 避免 new String("xxx") + "yyy" 这类冗余写法——额外创建无意义对象,徒增 GC 压力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











