Java StringBuilder

Java 中的 StringBuilder 类是一种可变字符串类型,它提供了一种高效的字符串操作方式。与 String 类不可变不同,StringBuilder 可以修改字符串的内容而不会创建新的对象。在本文中,我们将从四个方面介绍 StringBuilder 类,包括其实现原理、构造方法、重要方法以及需要注意的事项。

注意,StringBuffer 和 StringBuilder 在使用方式上几乎是完全相同的,所以不再单独介绍 StringBuffe。它们的主要的区别如下:

StringBuffer StringBuilder
线程安全
效率 低(因为线程安全加锁)
适用场景 多线程环境 单线程环境
初始容量 16 16
增长方式 翻倍+2 翻倍+2
API 同步方法 非同步方法
JDK 版本 JDK 1.0 JDK 1.5

StringBuilder 实现原理

StringBuilder 的实现原理是基于可变字符数组的动态扩容机制。StringBuilder 类在创建对象时会默认创建一个字符长度为 16 个字符的数组,具体的结构如下图所示。

创建的代码:

StringBuilder sb = new StringBuilder();
sb.append("wdbyte.com");
sb.append("1");

对应的逻辑图:

StringBuilder 构造

append() 方法中,StringBuilder 类会将要添加的字符串插入到字符数组,从而实现字符串的拼接,且不需要创建新的对象。

当需要添加的字符串长度超过当前字符数组长度时,StringBuilder 会使用Arrays.copyOf() 方法将字符数组扩容为原来的两倍加二。这在源码中可以看到。

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2; // 2 倍 + 2
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

可见,StringBuilder 内部就是维护了一个可以动态扩容的字符数组,在拼接字符时,如果数组尚有空间,就可以不用创建对象直接把字符放入到字符数组指定位置,以此来节省资源。

可能你已经发现 StringBuilder 的优势了,在进行大量字符串拼接时,StringBuilder 的效率要远高于 String 类型的字符串拼接。因为 String 类型的字符串拼接会涉及到多次创建新的字符串对象,而 StringBuilder 则可以通过动态扩容的方式避免这种性能问题。

StringBuilder 构造方法

StringBuilder 类有多个构造方法,其中最常用的是无参构造方法和带有初始值的构造方法。无参构造方法会创建一个空的 StringBuilder 对象,内部会创建一个默认长度为 16 的字符数组。而带有初始值的构造方法则会创建一个包含指定字符序列的 StringBuilder 对象,维护的字符数组长度为传入的字符串长度加上 16。

StringBuilder sb1 = new StringBuilder();
System.out.println(sb1.capacity()); // 容量:16
StringBuilder sb2 = new StringBuilder("wdbyte.com");
System.out.println(sb1.capacity()); // 容量:26

StringBuilder重要方法

StringBuilder 类提供了多个实用的方法,包括 append、insert、delete、replace 等。

方法名 功能解释
StringBuilder() 创建一个空的 StringBuilder 对象
StringBuilder(int capacity) 创建一个具有指定初始容量的 StringBuilder 对象
append(String str) 将指定字符串添加到此字符序列的末尾
insert(int offset, String str) 将指定字符串插入此字符序列中的指定位置
replace(int start, int end, String str) 用指定字符串替换此序列的子字符串
delete(int start, int end) 移除此序列的子字符串中的字符
reverse() 将此字符序列用其反转形式取代

append

append 方法用于将指定的字符串追加到当前 StringBuilder 对象的末尾。它有多个重载方法,可以接受不同类型的参数。

StringBuilder sb3 = new StringBuilder("www");
sb3.append(".wdbyte.com");
System.out.println(sb3.toString()); // www.wdbyte.com

insert

insert 方法用于将指定的字符或字符串插入到当前 StringBuilder 对象的指定位置。它也有多个重载方法,可以接受不同类型的参数。

StringBuilder sb4 = new StringBuilder("wdbyte");
sb4.insert(0,"www.");
System.out.println(sb4.toString()); // www.wdbyte
sb4.insert(10,".com");
System.out.println(sb4.toString()); // www.wdbyte.com

delete

delete 方法用于删除当前 StringBuilder 对象中指定位置的字符。它有两个重载方法,可以删除单个字符或一段字符。

StringBuilder sb5 = new StringBuilder("www.wdbyte.com");
sb5.delete(0,4);
System.out.println(sb5); // wdbyte.com

replace

replace 方法用于将当前 StringBuilder 对象中指定位置的字符替换为指定的字符或字符串。它也有多个重载方法,可以接受不同类型的参数。

StringBuilder sb6 = new StringBuilder("hello world!");
sb6.replace(6,11, "java"); // 结果为 "hello java!"

reverse

将此字符序列用其反转形式取代。

StringBuilder sb7 = new StringBuilder("hello world!");
sb7.reverse();
System.out.println(sb7); // 结果:!dlrow olleh

StringBuilder 注意事项

StringBuilder 对象的操作是非线程安全的,如果需要在多线程环境下使用字符串操作,建议使用 StringBuffer 类。此外,在创建 StringBuilder 对象时,如果预计字符串长度较长,可以通过构造方法传入初始容量,避免频繁扩容所带来的性能损失。

StringBuilder sb = new StringBuilder(100); // 初始容量为100 的 StringBuilder 对象

一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.