「OpenJdk-11 源碼-系列」AbstractStringBuilder,StringBuilder,StringBuffer

AbstractStringBuilder

AbstracStringBuilderStringBuilderStringBuffer 的父類。前面咱們講到String是一個不可變的字符串。而StringBuilderStringBuffer 則是對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 方法有不少重載。對於每種重載方法的內部實現大概能夠分爲下面幾步:函數

  1. 確保 append的值爲有效的。若是是字符串,那麼值若是爲 null,則會append一個null字符串,若是是longint的值是小於最小值,那麼會append一個固定值
  2. 擴容當前值。ensureCapacityInternal方法會將當前的char[] value值複製到一個新的char[] value中。
  3. 使用 getChars方法將append的值追加到擴容的value

StringBuilder & StringBuffer

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 thisui

上面的代碼咱們發現有這麼一行代碼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方法的時候,若是toStringCachenull的話,那麼就會調用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

相關文章
相關標籤/搜索