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适用要求线程安全的大量拷贝场景。
posted on 2018-03-13 16:03 xinghebuluo 阅读(535) 评论(0) 编辑 收藏 举报