JDK源碼-StringBuffer類

上文我們介紹過JDK源碼-StringBuilder類StringBuffer同StringBuilder類類似,也是爲了解決大量拼接字符串時產生很多中間對象問題,但是它和StringBuilder不同的是所有修改數據的方法都加上了synchronized,保證了線程安全,StringBuilder是線程不安全的,但是保證了線程安全是需要性能的代價的。使用場景:在多線程情況下,如有大量的字符串操作情況,應該使用StringBuffer。如HTTP參數解析和封裝等。


一、實現接口

StringBuffer和StringBuilder一樣,大部分方法中都會調用父類AbstractStringBuilder方法或屬性,實現了Serializable和CharSequence接口。

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

二、成員變量

toStringCache變量用於存儲StringBuffer對象維護的字符數組,並且被transient聲明,成員變量不參與序列化過程。

 private transient char[] toStringCache;

三、構造方法

StringBuffer構造方法同StringBuilder類類似

	//構造一個空的字符串緩衝區,並且初始化爲 16 個字符的容量。
	public StringBuffer() {
        super(16);
    }
    //創建一個空的字符串緩衝區,並且初始化爲指定長度 length 的容量。
    public StringBuffer(int capacity) {
        super(capacity);
    }
	//創建一個字符串緩衝區,並將其內容初始化爲指定的字符串內容 str,字符串緩衝區的初始容量爲 16 加上字符串 str 的長度。
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

    public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

四、其他方法

1、writeObject、readObject方法

writeObject(java.io.ObjectOutputStream s)在進行序列化的時候保存StringBuffer對象的狀態到一個流中,加了synchronized關鍵詞,保證線程安全。
readObject(java.io.ObjectInputStream s)反序列化時從流中獲取StringBuffer對象序列化之前的狀態。

	private synchronized void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        java.io.ObjectOutputStream.PutField fields = s.putFields();
        fields.put("value", value);
        fields.put("count", count);
        fields.put("shared", false);
        s.writeFields();
    }
    
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        java.io.ObjectInputStream.GetField fields = s.readFields();
        value = (char[])fields.get("value", null);
        count = fields.get("count", 0);
    }

2、toString()

此方法重寫了父類的toString()方法,創建了一個新的字符串對象,加了synchronized關鍵詞,保證線程安全。

	@Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

3、reverse()

此方法重寫了父類的reverse(),調用父類的方法實現反轉此字符串,toStringCache=null,目的是讓其指向一塊空內存,保證返回的對象不被StringBuffer的操作所影響。

	@Override
    public synchronized StringBuffer reverse() {
        toStringCache = null;
        super.reverse();
        return this;
    }

4、delete(int start, int end)

該方法重寫了父類的delete方法,調用父類方法指定刪除StringBuffer對象中指範圍內的子串。該類中還有deleteCharAt(int index),根據角標刪除字符,不再一一贅述。toStringCache=null,目的是讓其指向一塊空內存,保證返回的對象不被StringBuffer的操作所影響。

 	@Override
    public synchronized StringBuffer delete(int start, int end) {
        toStringCache = null;
        super.delete(start, end);
        return this;
    }

5、insert(int index, char[] str, int offset, int len)

該方法接受四個參數,第一個參數表示要插入的索引位置,第二個參數表示要插入的字符數組或者字符串,第三個參數和第四個參數用於截取該原字符數組。toStringCache=null;目的是讓其指向一塊空內存,保證返回的對象不被StringBuffer的操作所影響。

	@Override
    public synchronized StringBuffer insert(int index, char[] str, int offset, int len){
        toStringCache = null;
        super.insert(index, str, offset, len);
        return this;
    }
    
	public AbstractStringBuilder insert(int index, char[] str, int offset, int len){
        if ((index < 0) || (index > length()))
            throw new StringIndexOutOfBoundsException(index);
        if ((offset < 0) || (len < 0) || (offset > str.length - len))
            throw new StringIndexOutOfBoundsException(
                "offset " + offset + ", len " + len + ", str.length "
                + str.length);
        ensureCapacityInternal(count + len);
        System.arraycopy(value, index, value, index + len, count - index);
        System.arraycopy(str, offset, value, index, len);
        count += len;
        return this;
    }

6、append方法集

StringBuffer中的append方法都是重寫了父類中的append方法,toStringCache=null,目的是讓其指向一塊空內存,保證返回的對象不被StringBuffer的操作所影響。

	@Override
    public synchronized StringBuffer append(boolean b) {
        toStringCache = null;
        super.append(b);
        return this;
    }

    @Override
    public synchronized StringBuffer append(char c) {
        toStringCache = null;
        super.append(c);
        return this;
    }

    @Override
    public synchronized StringBuffer append(int i) {
        toStringCache = null;
        super.append(i);
        return this;
    }

    @Override
    public synchronized StringBuffer appendCodePoint(int codePoint) {
        toStringCache = null;
        super.appendCodePoint(codePoint);
        return this;
    }

    @Override
    public synchronized StringBuffer append(long lng) {
        toStringCache = null;
        super.append(lng);
        return this;
    }

    @Override
    public synchronized StringBuffer append(float f) {
        toStringCache = null;
        super.append(f);
        return this;
    }

    @Override
    public synchronized StringBuffer append(double d) {
        toStringCache = null;
        super.append(d);
        return this;
    }


五、總結

1、String是Java中基礎且重要的類,由於不可變性,在拼接字符串時候會產生很多無用的中間對象,如果頻繁的進行這樣的操作對性能有所影響。使用場景:在字符串不經常發生變化的業務場景優先使用String(代碼更清晰簡潔)。如常量的聲明,少量的字符串操作(拼接,刪除等)。

2、StringBuffer就是爲了解決大量拼接字符串時產生很多中間對象問題,所有修改數據的方法都加上了synchronized,保證了線程安全,但是保證了線程安全是需要性能的代價的。使用場景:在多線程情況下,如有大量的字符串操作情況,應該使用StringBuffer。如HTTP參數解析和封裝等。

3、StringBuilder解決了大量拼接字符串時產生很多中間對象問題,並且字符串拼接操作不需要線程安全。StringBuilder和StringBuffer他們其實和String差不多,內部一樣都是封裝的字符數組,只不過StringBuilder實現了動態擴容機制,可以動態擴容並且可以動態更改value數組中的元素而已,但本質上都是一樣的。在單線程情況下,如有大量的字符串操作情況,應該使用StringBuilder來操作字符串。使用場景:不能使用String"+"來拼接而是使用,避免產生大量無用的中間對象,耗費空間且執行效率低下(新建對象、回收對象花費大量時間)。如JSON的封裝等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章