String不可变、线程安全但性能低;StringBuilder可变、非线程安全、性能最高;StringBuffer可变、线程安全、性能居中;单线程拼接选StringBuilder,多线程共享修改才用StringBuffer,常量/键值等场景用String。

面试时回答这个问题,重点不是背定义,而是讲清楚“为什么有这三个类”以及“怎么选”。可以从三个核心维度展开:可变性、线程安全性、性能表现,再落到实际场景选择——逻辑清晰、有依据、不空泛。
1. 可变性决定底层行为
String 是不可变的(immutable),底层 char[] 或 byte[] 被 final 修饰,任何拼接、替换、截取操作都会生成新对象,原对象不变。比如 s += "a" 看似修改,实则是创建新 String 实例。
StringBuilder 和 StringBuffer 都是可变的(mutable),继承自 AbstractStringBuilder,底层用非 final 的 char[] 存储,所有 append、insert、delete 操作都在原数组上直接修改,仅在容量不足时扩容。
- String 修改 = 创建新对象 + 原对象保留 → 内存压力大
- StringBuilder/StringBuffer 修改 = 复用对象 + 动态扩容 → 内存友好
2. 线程安全性决定使用边界
String 天然线程安全:不可变 → 多线程读不会出错,无需同步。
立即学习“Java免费学习笔记(深入)”;
StringBuffer 是线程安全的:所有 public 修改方法(如 append、insert)都加了 synchronized,适合多线程共享同一个实例的场景。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
StringBuilder 是非线程安全的:方法没加锁,性能更高,但多个线程同时调用同一个实例的 append 可能导致内容错乱、count 错位等并发问题。
- 不要因为“怕出错”就默认用 StringBuffer —— 单线程下锁是纯开销
- 也不要以为“StringBuilder 快”就在多线程里共用它 —— 这是典型的隐蔽 bug 来源
3. 性能排序与典型误区
性能从高到低:StringBuilder > StringBuffer > String(频繁修改场景下)。
String 最慢不是因为“它慢”,而是因为每次修改都触发对象创建+数组拷贝+GC压力。循环中写 str += i,10000 次可能产生上万个临时 String 对象。
StringBuffer 比 StringBuilder 慢约 10%~15%(取决于 JVM 和操作密度),差距来自 synchronized 的进出开销和锁竞争可能。
- 编译器对 String 拼接有优化(如字节码转为 StringBuilder.append),但仅限于编译期可知的字符串常量拼接(如 "a" + "b")
- 运行期拼接(如循环中拼接变量)无法优化,必须手动用 StringBuilder
4. 场景化选择口诀
记三句话就够了:
- 值固定、做常量、当 key、要共享 → 用 String(如配置项、Map 键、SQL 模板)
- 单线程大量拼接/构建 → 无条件选 StringBuilder(如 JSON 组装、日志拼接、HTML 生成)
- 多线程共享一个字符串容器且需并发修改 → 才考虑 StringBuffer(注意:多数时候应改用局部变量 + StringBuilder,或加外部锁)
真实项目中,95% 以上的字符串构建场景都该用 StringBuilder;StringBuffer 更像是历史兼容产物,新代码除非明确需要线程安全且无法重构,否则不推荐主动选用。

















