二十四桥仍在,波心荡、冷月无声。

——姜夔《扬州慢》

## Java基础之StringBuffer和StringBuilder

1. 前言-浅谈String:

  1. String 类中使用 final 关键字修饰字符数组来保存字符串, private final char value[] ,所以String 对象是不可变的。
  2. String 中的对象是不可变的,也就可以理解为常量,线程安全。
  3. 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
  4. String类传送门…

2. 可变的StringBuffer和StringBuilder

  1. StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在AbstractStringBuilder 中也是使用字符数组保存字符串 char[] value 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
  2. StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,大家可以看下面的源码分析。

3. 线程安全性

AbstractStringBuilder 是 StringBuilder 与StringBuffer 的公共父类,定义了一些字符串的基本操作,如 append、insert、indexOf 等公共方法。

  • StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
  • StringBuilder 并没有对方法进行加同步锁,所以是线程不安全的。

4. 性能

StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。

相同情况下使用StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

5. AbstractStringBuilder部分源码

可变的字符序列–基于JDK1.8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
*可变的字符序列
*/
abstract class AbstractStringBuilder implements Appendable, CharSequence {

char[] value;//该值用于字符存储。
int count;//计数是使用的字符数。

// 此no-arg构造函数对于子类的序列化是必需的。
AbstractStringBuilder() {
}
// 创建指定容量的AbstractStringBuilder。
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
// 一系列方法...
}
5.1 StringBuffer部分源码

注意StringBuffer中方法中的synchronized锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public final class StringBuffer extends AbstractStringBuilder 
implements java.io.Serializable, CharSequence{

/**
*将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。
*toString返回的最后一个值的缓存。每当修改StringBuffer时清除。
*/
private transient char[] toStringCache;

static final long serialVersionUID = 3388685877147921107L;

/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}

public StringBuffer(int capacity) {
super(capacity);
}

public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}

public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}

@Override
public synchronized int length() {
return count;
}

@Override
public synchronized int capacity() {
return value.length;
}

/**
* 有一系列的方法的重载...
*/
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
/**
* 有一系列的方法的重载...
*/
@Override
public synchronized StringBuffer insert(
int index, char[] str, int offset,int len
){
toStringCache = null;
super.insert(index, str, offset, len);
return this;
}
}

length()和capacity()两个方法以及默认构造器的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("dd");
stringBuffer.append("ai");
stringBuffer.append("mm");
/**
* stringBuffer.length() = 6
* stringBuffer.capacity() = 16
*/
System.out.println("stringBuffer.length() = " + stringBuffer.length());
System.out.println("stringBuffer.capacity() = " + stringBuffer.capacity());

}
/**
* 当添加的字符超过16之后,该buffer容量为34
* stringBuffer.length() = 17
* stringBuffer.capacity() = 34
*/

一系列的重载方法:

image-20200714211713517

5.2 StringBuilder部分源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{

/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;

// 三个构造器和StringBuffer中的是一样的
public StringBuilder() {
super(16);
}

public StringBuilder(int capacity) {
super(capacity);
}

public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}

// 也是一系列的方法重载。
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}

public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}

// 也是一系列的方法重载。
@Override
public StringBuilder insert(
int index, char[] str, int offset,int len
){
super.insert(index, str, offset, len);
return this;
}

// ...
}

6. 小结:

  1. 操作少量的数据: 适用String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer