String
、StringBuffer
和 StringBuilder
是 Java 中常见的字符串操作类,它们主要的区别在于可变性、线程安全性和性能。
特性 | String |
StringBuffer |
StringBuilder |
---|---|---|---|
是否可变 | 不可变(Immutable) | 可变(Mutable) | 可变(Mutable) |
线程安全性 | 线程安全(但不可变,无需加锁) | 线程安全(内部使用 synchronized 关键字) | 非线程安全 |
性能 | 性能最低(因每次修改都创建新对象) | 性能较低(因线程安全同步机制) | 性能最高 |
适用场景 | 适用于少量字符串拼接或字符串内容不会变化的情况 | 适用于多线程环境下频繁修改字符串 | 适用于单线程环境下频繁修改字符串 |
使用场景 | 推荐的类 |
---|---|
字符串内容不会变,如存储常量字符串(e.g. final String name = "Hello"; ) |
String |
多线程环境,并且需要修改字符串(线程安全) | StringBuffer |
单线程环境,需要高效修改字符串 | StringBuilder |
字符串拼接较少,如 "Hello" + "World" |
String |
大量字符串拼接(如循环中追加字符串) | StringBuilder |
需要线程安全的字符串操作(如日志记录) | StringBuffer |
public class StringTest {
public static void main(String[] args) {
String str = "Hello";
str += " World"; // 创建了新的字符串对象 "Hello World"
System.out.println(str); // 输出: Hello World
}
}
注意:
str += " World";
会创建一个新的 String 对象,而不会修改原来的str
,这会导致大量的临时对象,影响性能。
public class StringBufferTest {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 直接修改sb对象,不创建新对象
System.out.println(sb.toString()); // 输出: Hello World
}
}
特点:
- 线程安全(内部方法使用
synchronized
关键字)。- 性能较 StringBuilder 低,但适用于多线程环境。
public class StringBuilderTest {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString()); // 输出: Hello World
}
}
特点:
- 不使用 synchronized,所以性能更高。
- 适用于单线程环境。
public class PerformanceTest {
public static void main(String[] args) {
int iterations = 100000; // 测试10万次字符串拼接
// 1. 使用 String
long startTime = System.currentTimeMillis();
String str = "";
for (int i = 0; i < iterations; i++) {
str += i; // 每次循环都会创建新的字符串对象
}
long endTime = System.currentTimeMillis();
System.out.println("String 耗时: " + (endTime - startTime) + " ms");
// 2. 使用 StringBuffer
startTime = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < iterations; i++) {
sb.append(i);
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer 耗时: " + (endTime - startTime) + " ms");
// 3. 使用 StringBuilder
startTime = System.currentTimeMillis();
StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb2.append(i);
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder 耗时: " + (endTime - startTime) + " ms");
}
}
String 耗时: 12500 ms
StringBuffer 耗时: 15 ms
StringBuilder 耗时: 10 ms
分析:
- String 拼接最慢,因为
str += i;
每次都会创建新对象,消耗大量时间。- StringBuffer 由于同步机制比 StringBuilder 略慢。
- StringBuilder 最快,适合单线程环境的字符串操作。
方法 | 说明 | 示例 |
---|---|---|
append(String str) |
追加字符串 | sb.append("Hello") |
insert(int offset, String str) |
在指定位置插入字符串 | sb.insert(5, "World") |
replace(int start, int end, String str) |
替换指定范围的内容 | sb.replace(0, 5, "Hi") |
delete(int start, int end) |
删除指定范围内的字符 | sb.delete(2, 5) |
reverse() |
反转字符串 | sb.reverse() |
capacity() |
返回当前容量 | sb.capacity() |
setLength(int newLength) |
设置字符串长度 | sb.setLength(10) |
类别 | 特点 | 适用场景 |
---|---|---|
String | 不可变,每次修改都会创建新对象 | 适用于少量字符串拼接或字符串内容不变的情况 |
StringBuffer | 可变,线程安全(synchronized) | 适用于多线程环境下的字符串拼接 |
StringBuilder | 可变,非线程安全,性能最高 | 适用于单线程环境下的高效字符串拼接 |
Q1:String 为什么是不可变的?
String
内部使用 final char[] 存储,任何修改都会生成新的对象,保证了线程安全和字符串常量池优化。Q2:为什么 StringBuilder 比 StringBuffer 性能更高?
StringBuffer
采用**synchronized
关键字**保证线程安全,而 StringBuilder
没有同步机制,因此性能更高。Q3:什么时候使用 StringBuffer 而不是 StringBuilder?
StringBuffer
。String
StringBuilder
StringBuffer