stringbuilder的capacity默认为16;带字符串构造时为字符串长度加16,如"abc"对应19;显式指定容量则直接采用;扩容时新容量为旧容量的1.5倍加1。

StringBuilder 的 capacity 不是当前长度,而是内部 char 数组能容纳的字符总数。它和 length(实际字符数)不同,理解 capacity 的行为对避免频繁扩容、提升性能很关键。
capacity 是怎么算出来的
StringBuilder 构造时若未指定容量,默认初始 capacity 为 16。这个值不是凭空来的——它来自无参构造器源码:super(16),即调用父类 AbstractStringBuilder 并分配一个长度为 16 的 char 数组。
当你用带字符串的构造器(如 new StringBuilder("hello")),capacity = 字符串 length + 16(例如 "hello" 长度为 5,则 capacity = 21)。
- 初始 capacity 可显式指定:
new StringBuilder(32)→ capacity = 32 - capacity 始终 ≥ length,但 length 变化不会自动改变 capacity
- capacity 只会在 append / insert 等操作导致数组不够时才增长
扩容机制:1.5 倍 + 1 是核心公式
当当前 char 数组已满(length == capacity),下一次 append 触发扩容。JDK 实际采用的逻辑是:
newCapacity = oldCapacity —— 即等价于 oldCapacity * 2 + 1?不完全是。更准确地说,主流 JDK(8~21)使用的是:
int newCapacity = (value.length (注意:这里的 value.length 是当前内部数组长度,即旧 capacity)
但真正生效的扩容逻辑在 expandCapacity(int minimumCapacity) 中:先尝试 oldCapacity * 2 + 2,如果仍不够,则直接设为 minimumCapacity(所需最小容量)。
- 例如:capacity=16,append 到第 17 个字符 → 扩容至 34(16×2+2)
- 再 append 至 35 → 扩容至 70(34×2+2)
- 若某次需要瞬间容纳 100 字符,而当前 capacity=70,则 newCapacity 直接取 max(70×2+2, 100) = 100
如何主动控制 capacity 避免反复扩容
如果你预先知道最终字符串大致长度(比如拼接 10 万个日志行),提前设置合理 capacity 能显著减少数组复制次数。
- 用
ensureCapacity(int minimumCapacity)提前预留空间(只增不减) - 用
trimToSize()在构建完成后释放冗余空间(将 capacity 设为当前 length) - 构造时直接指定:如
StringBuilder sb = new StringBuilder(1024); - 注意:capacity 设置过大也会浪费内存,需权衡;过小则触发多次 resize(每次涉及数组拷贝,O(n))
验证 capacity 变化的几个小技巧
可以通过反射或调试查看 value 数组长度,但最简单方式是结合 public API 观察:
-
sb.length()→ 当前字符数 -
sb.capacity()→ 当前数组总容量 - 连续调用
sb.append("x")并打印 capacity,可清晰看到 16→34→70→142… 的增长轨迹 - JDK 9+ 引入了 compact()(非 public),但 capacity 行为保持向后兼容
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











