String,StringBuilder和StringBuffer的特点和使用场景

这三个类是平时开发中经常遇到的,主要差别是运行速度和线程安全,使用起来String最方便了,另外两个稍微复杂一些。

从运行速度角度看,StringBuilder>StringBuffer>String。

从线程安全角度看,StringBuffer是线程安全的,StringBuilder和String不是。

下面从代码的角度分析一下,示例代码:

 1             StringBuilder strBuilder = new StringBuilder();
 2             strBuilder.append(100);
 3             strBuilder.append("123");
 4 
 5             StringBuffer strBuffer = new StringBuffer();
 6             strBuffer.append(100);
 7             strBuffer.append("123");
 8             
 9             String strTest = "start";
10             strTest += 100;
11             strTest += "123";

首选看下StringBuilder的实现:

 1     public StringBuilder append(int i) {
 2         super.append(i);
 3         return this;
 4     }
 5 
 6 public AbstractStringBuilder append(int i) {
 7         if (i == Integer.MIN_VALUE) { // 是否是最小值
 8             append("-2147483648");
 9             return this;
10         }
11        // 计算i的字符串长度,判断是否需要增大存储空间
12         int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
13                                      : Integer.stringSize(i);
14         int spaceNeeded = count + appendedLength;
15         ensureCapacityInternal(spaceNeeded);
16         Integer.getChars(i, spaceNeeded, value);  // 使用Integer的getChars方法,计算i的字符串值并把值拷贝到value中
17         count = spaceNeeded;
18         return this;
19     }
// 其中扩展空间时,会按照现有空间的2倍+2来扩展,保证不需要一直来扩展,提高效率
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
// 计算好扩展大小后,重新申请存储空间并把旧值拷贝到新的存储空间
value = Arrays.copyOf(value, newCapacity);
}
//Arrays.copyOf的实现
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength]; // 新申请空间,并拷贝
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
 1     public StringBuilder append(String str) {
 2         super.append(str);
 3         return this;
 4     }
 5 public AbstractStringBuilder append(String str) {
 6         if (str == null) str = "null";
 7         int len = str.length();
 8         ensureCapacityInternal(count + len);
 9         str.getChars(0, len, value, count);  // 使用了String的getChars方法把str拷贝到value中去
10         count += len;
11         return this;
12     }
13 
14 str.getChars代码:
15 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
16         if (srcBegin < 0) {
17             throw new StringIndexOutOfBoundsException(srcBegin);
18         }
19         if (srcEnd > value.length) {
20             throw new StringIndexOutOfBoundsException(srcEnd);
21         }
22         if (srcBegin > srcEnd) {
23             throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
24         }
25         // 最终使用 System.arraycopy完成字符串的拷贝
26         System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
27     }

再看下StringBuffer的实现:

1     public synchronized StringBuffer append(int i) { // 多了同步关键字,是线程安全的
2         super.append(i);  // 调用了AbstractStringBuilder的append方法,和StringBuilder使用的是一样的方法
3         return this;
4     }
1     public synchronized StringBuffer append(String str) { // 使用了同步关键字
2         super.append(str);  // 使用了AbstractStringBuilder的方法
3         return this;
4     }

从上面分析可以看到,StringBuffer和StringBuilder是继承了相同的父类AbstractStringBuilder,然后通过在方法上使用了同步关键字实现了线程安全,看下类定义:

1 public final class StringBuilder
2     extends AbstractStringBuilder
3     implements java.io.Serializable, CharSequence
4 {}
5 
6 public final class StringBuffer
7     extends AbstractStringBuilder
8     implements java.io.Serializable, CharSequence
9 {}

最后再看下String的操作,jvm会申请一段新的char数组,并把"start"和"100"顺序拷贝进去,第二次再申请一段新的char数组,并把"start100"和"123"顺序拷贝进去。

由于String的每次拷贝都会有申请新的存储空间和拷贝动作,而StringBuffer和StringBuilder只有在空间不够用的时候才会申请新的存储空间,因此从效率上讲String是最慢的。

综上所述,对String,StringBuilder和StringBuffer的使用做个小结:

1. String 适用次数较少的拷贝场景。

2. StringBuilder用无线程安全要求的大量拷贝场景。

2. StringBuffer用要求线程安全的大量拷贝场景。

原文地址:https://www.cnblogs.com/xinghebuluo/p/8557739.html