AbstracStringBuilder
是StringBuilder
和 StringBuffer
的父類。前面咱們講到String
是一個不可變的字符串。而StringBuilder
和 StringBuffer
則是對String
的一個補充,它們是可變的。先來看AbstractStringBuilder
的定義java
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
}
複製代碼
從類名上就能夠看出來它是一個抽象方法。而且實現了Appendable
以及Appendable
接口中的append
方法。使用了char[]
來保存值,而兩個構造函數也是子類所必需要實現的,用於初始化 char[]
的大小。安全
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
複製代碼
對於擴容,須要確保傳入的capacity
大於目前的value
的長度,且小於Integer.MAX_VALUE
(0x7fffffff)。在這個方法中首先把容量擴大爲原來的容量乘2加2,若是此時仍小於指定的容量,那麼就把新的容量設爲minCapacity
。而後判斷是否溢出,若是溢出了,把容量設爲MAX_ARRAY_SIZE(Integer.MAX_VALUE-8)
app
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;
}
//String.class
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);
}
複製代碼
對於 append
方法有不少重載。對於每種重載方法的內部實現大概能夠分爲下面幾步:函數
append
的值爲有效的。若是是字符串,那麼值若是爲 null
,則會append
一個null
字符串,若是是long
或int
的值是小於最小值,那麼會append
一個固定值ensureCapacityInternal
方法會將當前的char[] value
值複製到一個新的char[] value
中。getChars
方法將append
的值追加到擴容的value
後StringBuilder & StringBuffer
都實現了 AbstractStringBuilder
接口。他們最大的不一樣就是StringBuilder
是線程不安全的,而StringBuffer
是線程安全的。因此它們的屬性和方法大體都是同樣的,只是StringBuffer
的部分方法上添加了Synchronized
關鍵字來保證線程的安全。性能
//StringBuffer.class
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
複製代碼
在StringBuilder
中沒有synchronized
這個關鍵字。對於StringBuilder & StringBuffer
的大部分都是調用的父類的方法,只是最後多了一個 return this
。ui
上面的代碼咱們發現有這麼一行代碼toStringCache=null
,咱們來看看它的定義this
/** * A cache of the last value returned by toString. Cleared * whenever the StringBuffer is modified. */
private transient String toStringCache;
複製代碼
根據註釋,咱們能夠知道這個toStringCache
是用來緩衝最後一次 toString
的值,若是StringBuffer
被修改了的話,那麼toStringCache
就會被清空。接着再來看看 toString
方法spa
public synchronized String toString() {
if (toStringCache == null) {
return toStringCache =
isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}
return new String(toStringCache);
}
複製代碼
當調用toString
方法的時候,若是toStringCache
爲null
的話,那麼就會調用StringXXX.newString
方法。若是不爲null
的話,直接返回toStringCache
。而StringXXX.newString
的實現以下:線程
public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len),
LATIN1);
}
複製代碼
能夠發現它實際上是一個copy的操做。也就是說若是toStringCache
存在的話,就不須要再次進行copy。直接返回toStringCache
,這樣就能夠減小沒必要要的消耗,提高性能。code