StringBuilder性能优势源于可变字符数组和智能扩容策略:底层char[]可原地修改,扩容公式为old×2+2,非线程安全使其单线程拼接高效,但多线程需手动同步或改用StringBuffer。

StringBuilder 的性能优势,根植于它可变的底层结构和智能的扩容策略,而不是靠“魔法”。它不创建新对象,只在原数组上操作;容量不够时,也不是简单翻倍,而是有一套兼顾效率与内存的计算逻辑。
底层是可变字符数组,不是复制再建
String 用 final char[] 存字符,一旦初始化就不能改引用,所有操作都返回新对象。StringBuilder 则不同,它继承自 AbstractStringBuilder,内部是普通 char[] value(JDK 9+ 改为 byte[] + 编码标识),数组本身可被直接写入、覆盖、扩展。配合 int count 记录当前有效长度,length() 返回的就是 count,capacity() 返回的是 value.length —— 两者分离,支撑了真正的“原地修改”。
初始容量默认16,但别硬背,要看构造方式
不同构造方式决定起始数组大小:
- StringBuilder():初始容量为 16
- StringBuilder(int capacity):直接按传入值分配数组
- StringBuilder(String str):容量 = str.length() + 16(预留空间,避免刚拼接就扩容)
扩容不是简单×2,而是“旧×2+2”再兜底
当 append 等操作导致 count + 新增长度 > value.length 时,触发扩容。核心逻辑分三步:
立即学习“Java免费学习笔记(深入)”;
- 先算最小需容量:minimumCapacity = count + 新增字符数
- 再算新容量:newCapacity = oldCapacity × 2 + 2;如果这个值仍小于 minimumCapacity,就直接取 minimumCapacity
- 最后校验上限:不能超过 Integer.MAX_VALUE - 8,超限抛 OutOfMemoryError
扩容本质是 Arrays.copyOf(value, newCapacity) —— 一次数组复制,开销虽有,但远小于频繁新建 String 对象带来的 GC 压力。
非线程安全换来性能,用错场景反而拖后腿
StringBuilder 没加任何同步机制,所有方法都是普通实例方法。这意味着:
- 单线程高频拼接(如日志组装、JSON生成)—— 它是首选
- 多线程共享同一个 StringBuilder 实例 —— 必须手动加锁,否则结果不可预测;此时不如换用 StringBuffer,或每个线程独享一个 StringBuilder
- 仅拼接少量固定字符串(如 "a" + "b" + "c")—— 编译器会优化成常量,用 StringBuilder 反而多此一举



















