在 Java 中,String、StringBuffer和 StringBuilder都是用于处理字符串的类,但它们在可变性、线程安全性和性能方面有重要区别。以下是详细的对比:
1. String(字符串常量)
- 不可变性:
String对象创建后不可改变,任何修改操作都会生成新的对象 - 线程安全:由于不可变,天生线程安全
- 存储位置:字符串常量池(字面量)或堆内存(
new创建) - 性能:频繁修改时效率低(产生大量垃圾对象)
String str = "Hello";
str = str + " World"; // 创建了新对象,原对象未变
2. StringBuffer(字符串变量)
- 可变性:内容可以修改,不会创建新对象
- 线程安全:方法使用
synchronized关键字修饰,线程安全 - 性能:比
String在频繁修改时效率高得多 - 同步开销:由于同步,单线程环境下性能略低于
StringBuilder
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 在原对象上修改
3. StringBuilder(字符串变量)
- 可变性:同
StringBuffer,内容可修改 - 线程安全:非线程安全,没有同步
- 性能:在单线程环境下性能最高
- Java版本:JDK 1.5+ 引入
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 在原对象上修改
详细对比表
| 特性 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 可变性 | 不可变 | 可变 | 可变 |
| 线程安全 | 是(天生) | 是(同步) | 否 |
| 性能 | 最低(频繁修改时) | 中等(有同步开销) | 最高(无同步) |
| 使用场景 | 字符串不常修改 | 多线程环境字符串频繁修改 | 单线程环境字符串频繁修改 |
| 内存效率 | 低(频繁修改时) | 高 | 高 |
| 初始化 | String s = "abc";或 new String("abc") | new StringBuffer("abc") | new StringBuilder("abc") |
性能测试示例
public class PerformanceTest {
public static void main(String[] args) {
int N = 100000;
// String 测试
long start = System.currentTimeMillis();
String str = "";
for (int i = 0; i < N; i++) {
str += i; // 每次拼接都创建新对象
}
System.out.println("String 耗时: " + (System.currentTimeMillis() - start) + "ms");
// StringBuffer 测试
start = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < N; i++) {
sb.append(i);
}
System.out.println("StringBuffer 耗时: " + (System.currentTimeMillis() - start) + "ms");
// StringBuilder 测试
start = System.currentTimeMillis();
StringBuilder sbd = new StringBuilder();
for (int i = 0; i < N; i++) {
sbd.append(i);
}
System.out.println("StringBuilder 耗时: " + (System.currentTimeMillis() - start) + "ms");
}
}
使用建议
使用 String 的场景:
- 字符串不经常修改
- 需要字符串常量
- 线程安全要求高
- 作为 HashMap 的键(利用不可变性)
使用 StringBuffer 的场景:
- 多线程环境下频繁修改字符串
- 需要线程安全保证
使用 StringBuilder 的场景:
- 单线程环境下频繁修改字符串
- 性能要求高的场景
- 方法内部的局部变量
注意事项
- 编译器优化:现代 Java 编译器会对
String的+操作进行优化,在简单情况下自动使用StringBuilder - 循环中的字符串拼接:在循环中避免使用
String的+操作 - 线程安全选择:根据实际需求选择线程安全版本
总结
- 不可变 vs 可变:
String不可变,StringBuffer/StringBuilder可变 - 线程安全:
String和StringBuffer安全,StringBuilder不安全 - 性能:
StringBuilder>StringBuffer>String(频繁修改时)
根据具体场景选择合适的类,能显著提升程序性能。