Java StringBuilder详解
Java StringBuilder
详解
在 Java 中,StringBuilder
是一个高效的、可变的字符串操作类,用于在需要频繁修改字符串内容的场景下替代不可变的 String
。StringBuilder
提供了许多方法来支持字符串的拼接、插入、删除、替换等操作,且无需创建新的对象,提高了性能。
1. 为什么使用 StringBuilder
1.1 String 的局限性
String
是不可变的:每次对字符串进行修改(如拼接、替换等),都会创建一个新的字符串对象。- 如果在循环中频繁修改字符串,性能会非常低。
1.2 StringBuilder 的优势
StringBuilder
是可变的:对字符串的修改直接作用于当前对象,无需创建新对象。- 性能高:适合在需要频繁拼接或修改字符串内容时使用。
2. StringBuilder
的基本用法
2.1 创建 StringBuilder
对象
-
无参构造器:
StringBuilder sb = new StringBuilder();
创建一个初始容量为 16 的空
StringBuilder
。 -
指定初始容量:
StringBuilder sb = new StringBuilder(50);
创建一个初始容量为 50 的
StringBuilder
。 -
通过字符串初始化:
StringBuilder sb = new StringBuilder("Hello");
创建一个包含
"Hello"
的StringBuilder
,初始容量为16 + "Hello".length()
。
2.2 常用方法
-
append()
- 拼接字符串
将指定数据追加到末尾。StringBuilder sb = new StringBuilder("Hello"); sb.append(" World"); System.out.println(sb); // 输出: Hello World
- 支持多种数据类型:
String
,char
,int
,boolean
, 等。 - 方法链调用:
sb.append("Hello").append(" World");
- 支持多种数据类型:
-
insert()
- 插入字符串
在指定位置插入内容。StringBuilder sb = new StringBuilder("Hello"); sb.insert(5, " World"); System.out.println(sb); // 输出: Hello World
-
delete()
- 删除字符
删除从start
到end
索引(不包括end
)的字符。StringBuilder sb = new StringBuilder("Hello World"); sb.delete(5, 11); System.out.println(sb); // 输出: Hello
deleteCharAt()
- 删除指定索引的字符StringBuilder sb = new StringBuilder("Hello"); sb.deleteCharAt(4); System.out.println(sb); // 输出: Hell
-
replace()
- 替换字符串
替换从start
到end
索引之间的内容。StringBuilder sb = new StringBuilder("Hello World"); sb.replace(6, 11, "Java"); System.out.println(sb); // 输出: Hello Java
reverse()
- 反转字符串StringBuilder sb = new StringBuilder("Hello"); sb.reverse(); System.out.println(sb); // 输出: olleH
setCharAt()
- 修改指定索引的字符StringBuilder sb = new StringBuilder("Hello"); sb.setCharAt(0, 'h'); System.out.println(sb); // 输出: hello
toString()
- 转换为字符串StringBuilder sb = new StringBuilder("Hello"); String str = sb.toString(); System.out.println(str); // 输出: Hello
2.3 获取相关信息的方法
-
length()
- 获取长度StringBuilder sb = new StringBuilder("Hello"); System.out.println(sb.length()); // 输出: 5
-
capacity()
- 获取容量StringBuilder sb = new StringBuilder("Hello"); System.out.println(sb.capacity()); // 输出: 21 (16 + 5)
-
charAt()
- 获取指定索引的字符StringBuilder sb = new StringBuilder("Hello"); System.out.println(sb.charAt(1)); // 输出: e
-
substring()
- 截取子字符串StringBuilder sb = new StringBuilder("Hello World"); System.out.println(sb.substring(6)); // 输出: World System.out.println(sb.substring(0, 5)); // 输出: Hello
3. StringBuilder
和 StringBuffer
的区别
特性 | StringBuilder | StringBuffer |
---|---|---|
线程安全性 | 非线程安全 | 线程安全 |
性能 | 性能更高(无锁机制) | 性能较低(使用同步机制) |
推荐场景 | 单线程环境 | 多线程环境 |
4. 性能对比:String
vs StringBuilder
例子:使用 String
拼接
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // 每次都会创建新的 String 对象
}
System.out.println(result);
- 问题:每次
+
都会创建一个新的String
,导致大量内存消耗和性能开销。
例子:使用 StringBuilder
拼接
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i); // 直接操作内部数组,无需创建新对象
}
System.out.println(sb.toString());
- 优势:在内部修改字符串,性能远高于
String
。
5. 线程安全性:是否选择 StringBuffer
- 如果在单线程环境,推荐使用
StringBuilder
。 - 如果在多线程环境,需要线程安全,则使用
StringBuffer
。
6. 扩展:容量与扩容机制
初始容量
- 如果未指定,
StringBuilder
默认容量为 16。 - 如果通过字符串初始化,则容量为
16 + 字符串长度
。
扩容机制
- 如果追加内容超过当前容量,
StringBuilder
会自动扩容。 - 新容量计算公式:
newCapacity = ( oldCapacity × 2 ) + 2 \text{newCapacity} = (\text{oldCapacity} \times 2) + 2 newCapacity=(oldCapacity×2)+2
7. 示例代码:全面操作
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
// 追加
sb.append(" World");
System.out.println(sb); // Hello World
// 插入
sb.insert(6, "Java ");
System.out.println(sb); // Hello Java World
// 删除
sb.delete(5, 10);
System.out.println(sb); // Hello World
// 替换
sb.replace(6, 11, "Java");
System.out.println(sb); // Hello Java
// 反转
sb.reverse();
System.out.println(sb); // avaJ olleH
// 获取子字符串
System.out.println(sb.substring(0, 4)); // avaJ
// 转换为字符串
String result = sb.toString();
System.out.println(result); // avaJ olleH
}
}
总结
StringBuilder
是一个高效的字符串操作类,适合在单线程环境下频繁操作字符串的场景。通过灵活的方法(如 append
, insert
, delete
等),可以满足大多数字符串修改需求,同时避免了 String
带来的性能瓶颈。对于线程安全需求,可以选择 StringBuffer
。