StringBuilder类源码剖析

StringBuilder类源码剖析

一、StringBuilder类的简介

StringBuilder是可变字符序列。此类提供与StringBuffer兼容的API,但不保证同步。此类设计用于在单个线程使用字符串缓冲区的场景下用作StringBuffer的直接替代(通常情况如此)。==在可能的情况下,建议优先使用此类而不是StringBuffer,因为它在大多数实现下会更快。==每个StringBuilder都有一个容量,只要StringBuilder中包含的字符序列的长度不超过容量,就不需要分配新的内部缓冲区。如果内部缓冲区溢出,它会自动扩容

==StringBuilder的实例对于多线程使用是不安全的。如果需要此类同步,则建议使用StringBuffer。==除非另有说明,否则将null参数传递给此类中的构造函数或方法将导致引发NullPointerException。

image-20230913142919691

image-20230913142906265

二、StringBuilder类的构造方法

StringBuilder的构造方法其实都是调用了父类AbstractStringBuilder的构造方法,总的来说无非就是是否指定初始字符序列是否指定初始容量注意指定了初始字符序列后容量=字符序列的长度+16,为以后的appendinsert等操作预留了空间。

image-20230913144049464

1
2
3
public StringBuilder() {
super(16);
}

image-20230913144101317

1
2
3
public StringBuilder(int capacity) {
super(capacity);
}

image-20230913144125922

1
2
3
4
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}

image-20230913144147848

1
2
3
4
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}

三、StringBuilder类的方法

与构造函数类似,StringBuilder的所有方法基本都是通过调用父类的相应方法实现的,重点在于父类AbstractStringBuilder,参考之前的AbstractStringBuilder类源码剖析

image-20230913145051809

四、StringBuilder类的toString方法

toString方法会创建一个新字符串(深拷贝),不会共享底层存放字符数据的字节数组,因此时间复杂度与空间复杂度都是O(n)。

1
2
3
4
5
public String toString() {
// Create a copy, don't share the array
return isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}

五、StringBuilder类的序列化/反序列化

writeObject方法将StringBuilder实例的状态保存到流中,也就是序列化实例。defaultWriteObject方法可以简单理解一下:

image-20230913151256306

1
2
3
4
5
6
7
8
9
10
11
12
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
char[] val = new char[capacity()];
if (isLatin1()) {
StringLatin1.getChars(value, 0, count, val, 0);
} else {
StringUTF16.getChars(value, 0, count, val, 0);
}
s.writeObject(val);
}

readObject方法从流中恢复StringBuilder实例的状态,也就是反序列化。defaultReadObject方法与defaultWriteObject方法类似。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
char[] val = (char[]) s.readObject();
initBytes(val, 0, val.length);
}

// AbstractStringBuilder.initBytes
void initBytes(char[] value, int off, int len) {
if (String.COMPACT_STRINGS) {
this.value = StringUTF16.compress(value, off, len);
if (this.value != null) {
this.coder = LATIN1;
return;
}
}
this.coder = UTF16;
this.value = StringUTF16.toBytes(value, off, len);
}