StringBuffer類用於字符串的拼接,由於它動態改變字符數組的長度並且事先會留有冗餘長度,而不是像String拼接一樣不斷的重新創建新的String對象,所以速度上StringBuffer是快過String類的
從StringBuffer源碼可以看到它是繼承了AbstractStringBuilder類的,這個類暫時先不管他,我們主要看一下StringBuffer類的append方法
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
我們主要看參數爲String類型的append方法,其餘重載方法要麼調用該方法要麼也與其實現方式大同小異
先不管這個toStringCache參數,字面意思上可以大概知道該參數是用來做緩存的,我們從這個方法進入到其父類AbstarctStringBuilder的append方法中
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;
}
先看第一步,這裏調用了appendNull方法,看看這個方法
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
這個方法實際上就是拼接了“null”字符串,回到第二步,看實現字符數組長度適應的ensureCapacityInternal方法
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
這個方法傳入了一個最小長度,如果當前字符數組長度不夠,便調用Arrays.copyOf方法改變value長度,看看這個方法
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;
}
這個copyOf方法中創建了一個新的字符數組,並用arraycopy方法將原來數組的內容存了進行
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 代碼解釋: Object src : 原數組 int srcPos : 從元數據的起始位置開始 Object dest : 目標數組 int destPos : 目標數組的開始起始位置 int length : 要copy的數組的長度 將src數組從srcPos位置開始,複製長度爲length的內容到dest數組,起始位置爲destPos
回到ensureCapacityInternal方法,可以看到它讓value重新指向了這個新創建的字符數組從而實現了數組長度的變化
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
在看append方法的第三部,調用了String.getChars方法進行內容的拼接,而getChars在一系列校驗之後最終是調用native層的getCharsNoCheck方法,
native void getCharsNoCheck(int start, int end, char[] buffer, int index) 代碼解釋: int start : 起始位置 int end : 終止位置 char[] buffer : 目標數組 int index : 目標數組的開始起始位置 將該字符串從start到end的內容複製到buffer數組,起始位置爲index
於是再看AbstractStringBuilder.append方法,便一目瞭然,最後改變一下當前的字符內容長度並返回
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;
}