我们为什么要用StringBuffer 代替String+
直接进入话题: 为啥字符串拼接我们都是采用StringBuffer 而很少采用String + 的方式呢?简单的阐述下原因:
执行效率问题,String + 拼接方式简单粗暴,对于常量池没有的字符串会生成对应的字符串常量,占据了对应的空间,拼接数量愈多,效率越是低下;而SpringBuffer 不同,他的原理是利用字符数组的扩容,以及字符的复制原理达到对应的拼接效果,只是在原有数组进行扩容,然后再追加对应的值,显然StringBuffer效率更加高效。
那让我们具体结合源码来更加的了解这个StringBuffer 这位小朋友吧。
一、设计的类:
StringBuffer、 AbstractStringBuilder、Arrays
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
StringBuffer 继承了AbstractStringBuilder,append 的具体方法再他的父类,也就是AbstractStringBuilder 这里具体实现,如图:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); //1、这里进行字符数组的扩容
str.getChars(0, len, value, count); //2、这里进行字符数组的追加
count += len;
return this;
}
二、我们具体看下nsureCapacityInternal(count + len); 中的逻辑,如图:
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2; //1、建立最新的容量
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);//2、扩容之后的字符数组赋值
}
expandCapacity 这个方法主要做了两件事情:
1、对StringBuffer 的容量之进行新的扩容,之前值的长度 两倍+2 ;
2、对原来数组进行扩容,原有值不变。
接下来我们再看下 str.getChars(0, len, value, count); 的源码,如下:
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); //进行对目标数组的拼接。
}
很明显,getChars 这个方法的主要作用就是对原有数组进行追加对应的字符串。
OK ,目前就是本人站在源码的角度上分析了SpringBuffer 中append方法的原理,其实这个方法就做了两件事,对数组进行扩容,扩容之后我在追加对应的值。