StringBuilder扩容机制先判断count+新增字符数是否超过value.length,超则触发扩容;新容量为Math.max(旧capacity×2+2, minCapacity),其中minCapacity=当前count+新增字符长度。

面试中问“StringBuilder扩容机制怎么算”,核心是考察你是否真正理解容量(capacity)、长度(length)和扩容公式三者的关系,而不是死记硬背。关键不在“背公式”,而在“会推演”。
扩容触发条件:先看够不够用
每次调用 append、insert 等修改方法时,JVM会立即检查:
当前已用长度(count) + 新增字符数 > 当前数组长度(value.length)?
如果成立,就触发扩容;否则直接写入,不扩容。
注意:
• length() 返回的是 count(已用字符数)
• capacity() 返回的是 value.length(底层数组总长度)
• 初始 capacity 默认为 16(无参构造)
新容量怎么算:两步逻辑,不是简单乘2
扩容不是“一律翻倍”,而是按需计算,分两步:
-
第一步:算出最小需要容量(minCapacity)
minCapacity = 当前 count + 新增字符长度 -
第二步:确定实际分配容量(newCapacity)
newCapacity = Math.max(旧 capacity × 2 + 2, minCapacity)
例如:
• 初始 capacity = 16,count = 16(已填满)
• append("a") → minCapacity = 16 + 1 = 17
• 计算基础扩容:16 × 2 + 2 = 34
• 因为 34 ≥ 17,所以 newCapacity = 34
再如:
• capacity = 16,count = 0(空对象)
• append("01234567890123456789")(20个字符)→ minCapacity = 0 + 20 = 20
• 基础扩容 = 16 × 2 + 2 = 34,仍 ≥ 20 → newCapacity = 34
又如:
• capacity = 16,count = 10
• append("123456789012345678901234567890")(30个字符)→ minCapacity = 10 + 30 = 40
• 基础扩容 = 16 × 2 + 2 = 34
扩容的代价:一次复制,一次丢弃
扩容本质是:
• 分配一个更大 char[](或 byte[],Java 9+ Compact Strings)
• 用 Arrays.copyOf 或 System.arraycopy 把旧数组内容拷过去
• 原数组失去引用,等待 GC 回收
这意味着:
• 扩容本身是 O(n) 操作,但摊还后 append 平均仍是 O(1)
• 频繁扩容会导致内存波动和 GC 压力(实测 10 万次 append 可能扩 5 次)
• 若预估最终长度,建议用 new StringBuilder(预估大小) 避免多次扩容
常见陷阱题怎么答
面试官可能这样问:
-
“new StringBuilder().append('a').length() 和 capacity() 各是多少?”
→ length = 1,capacity = 16(未扩容) -
“连续 append 17 个字符,扩容几次?新容量多少?”
→ 第 17 个字符触发扩容,从 16→34,只扩 1 次 -
“为什么是 ×2+2,不是 ×2?”
→ 防止初始 capacity=0 时计算错误(0×2+2=2,有安全下界);+2 是工程经验,平衡空间与次数 -
“StringBuilder 线程安全吗?为什么?”
→ 不安全;底层没加 synchronized,所有方法非同步;StringBuffer 才加了


















