问题来源:在Java中,使用String str = “a" + "b" + “c"的时候,编译器会自动优化,使用StringBuilder来完成连接操作,那么,StringBuffer为什么比起String性能更高呢?
首先,以上字符串的连接,按照Java中字符串是常量不可更改的特性,理应是先有一个新的变量指向"a",而后再创建一个变量,指向"a + b",依次类推。但是按照这种方法,会产生很多没用的中间变量,严重影响了性能,所以实际中,编译器会自动创建StringBuilder优化性能。
StringBuilder中的append方法源码:
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
在AbstractStringBuilder中,数据是放在一个 char[ ] value的数组里的。
由于StringBuffer继承自AbstractStringBuilder,所以查看父类的append方法:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);<span style="white-space:pre"> </span>//这里传入的参数是增加字符串以后所需要的数组的最小长度
str.getChars(0, len, value, count);
count += len;
return this;
}
对该方法的进一步理解——ensureCapacityInternal()源码:
/**
* This method has the same contract as ensureCapacity, but is
* never synchronized.
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)<span style="white-space:pre"> </span>//如果最小长度大于原来的数据长度,则扩容
expandCapacity(minimumCapacity);
}
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.这里是扩容的具体实现
*/
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;<span style="white-space:pre"> </span>//注意这里的扩容不是简单的用 原始长度 + 新字符串长度
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);<span style="white-space:pre"> </span>//这里是通过Arrays的copyof方法,构造一个新的长度的数组,并把原来的数据拷贝进去
}<span style="white-space:pre"> </span>//通过这样的方法,实现了数组的扩容
对该方法的进一步理解——String中的getChars方法:
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);
}
这个方法的目的是,从数组dst[ ]的dstBegin开始,将原始数据从srcBegin开始到srcEnd-1结束的字符串拷贝进来。此处String中的value,指的是String的原始字符串,即调用这个方法的那个字符串。
以上,即为StringBuffer中append方法的完整过程