目录
- 一. String:不可变的字符串
- 二.StringBuilder:可变字符串
- 三.StringBuffer:线程安全的可变字符串
- 四.总结
在 Java 开发中,字符串处理是日常编码中最频繁的操作之一。String、StringBuilder 和 StringBuffer 这三个类虽然都用于操作字符串,但在性能、线程安全性和使用场景上存在显著差异。
一. String:不可变的字符串
String 类是 Java 中最基础的字符串类,其底层实现具有不可变性:
存储结构:在 JDK 8 及之前,String 内部通过 private final char value[] 数组存储字符;JDK 9 及以上改为 byte[] 数组(根据编码自动选择存储方式,节省内存)。
不可变性:value 数组被 final 修饰,意味着一旦 String 对象创建,其内部的字符序列就无法被修改。任何看似 “修改” 的操作(如拼接、截取)都会创建新的 String 对象,原对象保持不变。
String str = "hello";
str += " world"; // 实际创建了新的 String 对象,原 "hello" 仍存在于内存中
这种设计的优势是:
天然线程安全(多线程只能读取,无法修改) 可作为 HashMap 等集合的键(哈希值不会变化) 字符串常量池复用,节省内存
但缺点也很明显:频繁修改会产生大量临时对象,导致 GC 压力增大,性能下降。
二.StringBuilder:可变字符串
存储结构:内部通过 char[] value 数组存储(无 final 修饰),支持动态扩容。
默认初始容量为 16; 当字符长度超过当前容量时,会创建一个新的数组(容量为原容量的 2 倍 + 2),并将原数据复制到新数组中。
可变性:所有修改操作(如 append()、insert()、delete())都直接操作底层数组,不会创建新对象(除非需要扩容)。
StringBuilder sb = new StringBuilder("hello");
sb.append(" world"); // 直接在原数组上修改,不创建新对象
由于省去了创建新对象的开销,且没有同步锁的消耗,StringBuilder 成为单线程下字符串拼接的首选。
三.StringBuffer:线程安全的可变字符串
tringBuffer 是早期 Java 提供的可变字符串类,与 StringBuilder 最大的区别是线程安全性:
存储结构:与 StringBuilder 基本一致,内部也是 char[] value 数组。
线程安全:通过在所有公共方法上添加 synchronized 关键字实现线程安全,确保多线程环境下的操作原子性。
public synchronized StringBuffer append(String str) {// 具体实现
}
这种设计保证了线程安全,但也带来了同步锁的性能开销,因此在单线程环境下效率低于StringBuilder。