Java String不可变性决定拼接性能:编译期字面量拼接被优化,运行期含变量则每次新建对象;+=隐式创建StringBuilder,循环拼接开销大;拼接结果通常不入常量池;作为HashMap key时应避免临时拼接。

Java String 的不可变性不是拼接时的“障碍”,而是优化决策的起点——它决定了哪些拼接方式安全、高效,哪些会悄悄拖垮性能。
拼接前先看引用是否真的变了
String 不可变,意味着每次 + 或 concat() 都会生成新对象。编译器能识别部分简单场景做优化,但仅限于编译期已知的字面量拼接:
-
编译期优化:如
"a" + "b" + "c"会被直接合并为"abc",不产生中间对象 -
运行期失效:一旦含变量(如
s + "x"),JVM 就无法提前合并,每次都会新建 String 对象 -
反例验证:用
==比较拼接前后引用,基本都是false,说明内存地址已变
从字节码看出“假修改”的本质
javac 编译后,s += "x" 实际被转成类似 s = new StringBuilder().append(s).append("x").toString() 的调用(JDK 9+)。这不是语法糖的“聪明”,而是对不可变性的被动适配:
- 每次
+=都隐式创建 StringBuilder → append → toString,开销叠加 - 循环中写
result += item,等于每轮都新建 StringBuilder 和 String,浪费严重 - 用
javap -c查看字节码,能看到new java/lang/StringBuilder指令反复出现
常量池复用提醒你:别在不该拼的地方拼
String 不可变支撑了常量池机制,但拼接结果几乎不会进常量池(除非显式调用 intern()):
立即学习“Java免费学习笔记(深入)”;
-
String a = "hello"; String b = "world"; String c = a + b;→c在堆中,不在常量池 -
"hello" + "world"(全字面量)→ 编译期合并,结果进常量池 - 想复用?优先用静态 final 字符串组合,或预计算好放入常量池,而非运行时拼
哈希缓存优势反向提示:key 类型别乱拼
String 作为 HashMap key 高效,靠的是 hashCode 一次计算、永久缓存。但若 key 是拼接得来:
- 每次拼接都新建对象,hashCode 虽缓存,但对象本身生命周期短、GC 压力大
- 更关键的是:拼接逻辑若含业务变量,key 可能重复创建,失去常量池复用价值
- 建议:key 尽量用原始字面量、final 常量,或用 StringBuilder 构建后立即转 String 并复用引用


















