String与StringBuffer与StringBuilder的区别

String与StringBuffer与StringBuilder的区别

1.可变性

String内部的value值是final修饰的,所以它是一个不可变的类,每一次修改String的值的时候,都会产生一个新的对象。

StringBuffer和StringBuilder是一个可变类,字符串的变更不会产生新的对象。

2.线程安全性

String是一个不可变的类,是线程安全的。

StringBuffer也是线程安全的,因为它的每个操作方法里面都用了Synchronized同步关键字。

StringBuilder它不是线程安全的。

所以在多线程环境下,对字符串进行操作,我应该使用StringBuffer。

3.性能方面

String是性能最低的,因为不可变,意味着做字符串拼接或者修改的时候,我们需要重新去创建新的对象以及分配内存。

StringBuffer要比String的性能更高一点,因为它的可变性,意味关字符串可以直接被修改。

StringBuilder性能最高,因为无锁。

4.存储方面

String存储在字符串常量池中。StringBuilder和StringBuffer存储在堆内存空间。

StringBuilder和StringBuffer都是AbstractStringBuilder抽象类的实现类。

源码

String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {

public static void main(String[] args) {
String str1 = "a";
String str2 = new String("a");
String strTmp = "";
String str3 = "a" + strTmp;
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str1 == str2);
System.out.println(str1 == str3);
}

}
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
private final char value[];	
public String() {
this.value = "".value;
}

public String(String original) {
this.value = original.value;
this.hash = original.hash;
}

public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}

public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}

public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= codePoints.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > codePoints.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}

final int end = offset + count;

// Pass 1: Compute precise size of char[]
int n = count;
for (int i = offset; i < end; i++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
continue;
else if (Character.isValidCodePoint(c))
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}

// Pass 2: Allocate and fill in char[]
final char[] v = new char[n];

for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
v[j] = (char)c;
else
Character.toSurrogates(c, v, j++);
}

this.value = v;
}

可以看到内部变量value使用的是final修饰的。

1
2
3
this.value = Arrays.copyOf(value, value.length);

this.value = Arrays.copyOfRange(value, offset, offset+count);

内部同样有

1
char[] v = new char[n];

相当于新申请了一块内存空间。

StringBuilder

1
2
3
public StringBuilder() {
super(16);
}
1
2
3
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
1
2
3
4
5
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
1
2
3
4
5
6
7
8
9
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
1
2
3
4
5
6
7
8
9
10
11
12
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

发现这里没有使用新的char数组

StringBuffer

1
2
3
4
5
6
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}

只是在方法上加了synchronized关键字。


String与StringBuffer与StringBuilder的区别
http://hanqichuan.com/2019/07/18/java/String与StringBuffer与StringBuilder的区别/
作者
韩启川
发布于
2019年7月18日
许可协议