StringBuilder 与 String 的根本区别在于可变性:String 不可变,每次拼接生成新对象;StringBuilder 可变,通过修改内部 char[] 数组实现高效拼接,避免频繁对象创建和 GC。

Java 中 StringBuilder 是高频面试考点,核心不在于背 API,而在于理解它和 String、StringBuffer 的本质差异,以及在什么场景下该用、为什么能提升性能。
StringBuilder 和 String 的根本区别在哪?
String 是不可变(immutable)的,每次拼接都生成新对象,旧对象若无引用会被 GC;StringBuilder 是可变(mutable)的,内部用 char[] 数组承载内容,append() 等操作直接修改数组,避免频繁创建对象。
- String s = "a" + "b" + "c"; → 编译期优化为常量池中一个字符串,不触发 StringBuilder
- String s = ""; for(int i=0; i
- 正确写法:StringBuilder sb = new StringBuilder(); for(...) sb.append("x"); String result = sb.toString();
StringBuilder 和 StringBuffer 该怎么选?
两者 API 几乎一致,关键区别是线程安全性:
- StringBuffer 所有 public 方法都加了 synchronized,适合多线程环境但有同步开销
- StringBuilder 方法非同步,单线程下性能更高(通常快 10%–15%)
- 面试常问:“能否把 StringBuilder 用在多线程里?”——可以,但必须由调用方保证线程安全(如加锁、局部变量、不可共享),不能依赖其自身同步
StringBuilder 的扩容机制怎么影响性能?
默认初始容量是 16。当 append 超出当前 char[] 长度时,会扩容:newCapacity = oldCapacity * 2 + 2。这个公式意味着容量呈近似翻倍增长。
立即学习“Java免费学习笔记(深入)”;
- 频繁扩容会触发数组复制(System.arraycopy),带来额外开销
- 如果预估最终长度(比如拼接 1000 个字符串,平均长度 10),建议构造时指定容量:new StringBuilder(10000)
- 注意:capacity() 返回当前数组长度,length() 返回实际字符数;setLength(n) 可截断或补 \u0000,但不会改变 capacity
哪些典型场景必须用 StringBuilder?
不是所有拼接都要手动用 StringBuilder,JVM 会对简单字符串字面量拼接做优化。重点看运行期动态拼接:
- 循环内字符串累加(尤其次数不确定或较多)
- 日志拼接(如 log.info("user=" + u.getId() + ", action=" + act))→ 推荐用占位符(SLF4J),底层也是 StringBuilder
- JSON/XML 字符串组装(未用 Jackson/Gson 等库时)
- SQL 拼接(注意防 SQL 注入,实际应优先用 PreparedStatement)
不复杂但容易忽略:理解“可变性”和“无同步”是设计初衷,用对场景比记住方法名更重要。


















