JDK源碼閱讀03---------AbstractStringBuilder、StringBuffer、StringBuilder

1.AbstractStringBuilder、StringBuffer、StringBuilder類簡介

字符串廣泛應用 在Java 編程中,在 Java 中字符串屬於對象,Java 提供了 String 類來創建和操作字符串。

需要注意的是,String的值是不可變的,這就導致每次對String的操作都會生成新的String對象,這樣不僅效率低下,而且大量浪費有限的內存空間。

String是Java語言非常基礎和重要的類,提供了構造和管理字符串的各種基本邏輯。它是典型的Immutable類,被聲明成爲final class,所有屬性也都是final 的。也由於它的不可變性,類似拼接、裁剪字符串等動作,都會產生新的String對象。由於字符串操作的普遍性,所以相關操作的效率往往對應用性能有明顯影響

StringBuffer是爲解決上面提到拼接產生太多中間對象的問題而提供的一個類,我們可以用append或者add方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本質是一個線程安全的可修改字符序列,它保證了線程安全,也隨之帶來了額外的性能開銷,所以除非有線程安全的需要,不然還是推薦使用它的後繼者,也就是StringBuilder.

StringBuilder是Java 1.5中新增的,在能力上和StringBuffer沒有本質區別,但是它去掉了線程安全的部分,有效減小了開銷,是絕大部分情況下進行字符串拼接的首選。

StringBufferStringBuilder 底層都是利用可修改的(char,JDK 9 以後是 byte)數組,二者都繼承了AbstractStringBuilder,裏面包含了基本操作,區別僅在於最終的方法是否加了 synchronized

2.源碼閱讀

StringBufferStringBuilder都是繼承的AbstractStringBuilder,二者中的主要方法與變量與AbstractStringBuilder都類似,StringBufferStringBuilder 的區別主要在於最終的方法是否加了synchronized關鍵字,這裏源碼主要以AbstractStringBuilder爲主,有區別的地方再另行標註。

  • 2.1 類定義
/**
	 *AbstractStringBuilder
     	*實現了兩個接口,其中CharSequence這個字符序列的接口已經很熟悉了:
	   該接口規定了需要實現該字符序列的長度:length();
		可以取得下標爲index的的字符:charAt(int index);
		可以得到該字符序列的一個子字符序列: subSequence(int start, int end);
		規定了該字符序列的String版本(重寫了父類Object的toString()):toString();
		
	   Appendable接口顧名思義,定義添加的’規則’:
		append(CharSequence csq) throws IOException:如何添加一個字符序列
		append(CharSequence csq, int start, int end) throws IOException:如何添加一個字符序列的一部分
		append(char c) throws IOException:如何添加一個字符
     *
     */
	abstract class AbstractStringBuilder implements Appendable, CharSequence {}
	
	public final class StringBuffer    extends AbstractStringBuilder implements java.io.Serializable, CharSequence{}

	public final class StringBuilder    extends AbstractStringBuilder    implements java.io.Serializable, CharSequence{}
  • 2.2變量
    AbstractStringBuilder
/**
     * 用於存儲字符序列的緩衝數組
     */
    char[] value;

    /**
     * 用於存儲實際存儲的字符數量
     */
    int count;
    
	 /**
     * 緩衝數組最大長度(2^31-1)-8 約爲21億
     */
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

StringBuffer中特有的toStringCache,用來緩存StringBuffer最近一次toString的值,當StringBuffer出現任何其他操作或修改後,清空緩存值。

 /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;
  • 2.3構造方法
    AbstractStringBuilder
    AbstractStringBuilder() {
    }
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

StringBuilder與StringBuffer的構造器基本相同,默認初始化數組長度爲,構建時初始字符串長度加 16

public StringBuffer() {
        super(16);
    }
    public StringBuffer(int capacity) {
        super(capacity);
    }
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }
    public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }
  • 2.4常用方法
    /**
     * 獲取字符串長度
     */
    @Override
    public int length() {
        return count;
    }
    
    /**
     * 獲取緩衝區的容量
     */
    public int capacity() {
        return value.length;
    }

擴容相關實現:
擴容時,當現有容量值*2+2<所需最小容量時,取所需最小容量
現有容量值*2+2>=所需最小容量時,取 現有容量*2+2

 /**
     * 緩衝數組容量校驗
     * 放入緩衝數組所需要的的最小容量 
     */
    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));
        }
    }

    /**
     * 緩衝數組最大長度(2^31-1)-8 約爲21億
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     *  創建一個新容量的數組:
     *  當所需新容量>現有容量*2+2 時,取所需新容量大小
     *  當新建新容量大小<0時,取最小容量
     *  
     */
    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;
    }
	/**
     *  當新建新容量>Integer.MAX_VALUE時,拋OutOfMemoryError();
     *  當 MAX_ARRAY_SIZE<minCapacity <Integer.MAX_VALUE時,取minCapacity 
     */
    private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

關於“空格”相關的方法:

	/**
     *  將緩存數組中的非空字符序列拷貝到新的數組中
     */
		public void trimToSize() {
	        if (count < value.length) {
	            value = Arrays.copyOf(value, count);
	        }
	    }

    /**
     * 該函數沒有返回值。 
	   若參數 newLength 大於或等於原長度,原來字符串裏的字符位置不變,新多出來的位置					    	用 空字符(‘\0’)填充; 
	   若參數 newLength 小於原長度,就相當於在原字符串上截取 newLength 長度的字符串。 
newLength >= 0
     */
    public void setLength(int newLength) {
        if (newLength < 0)
            throw new StringIndexOutOfBoundsException(newLength);
        ensureCapacityInternal(newLength);
        if (count < newLength) {
            Arrays.fill(value, count, newLength, '\0');
        }
        count = newLength;
    }

AbstractStringBuilder中的append()方法,主要實現思路就是先確定容量,再通過getChars()方法或者遍歷字符來將所需要的字符串信息追加至緩衝數組中.

 public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    
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;
    }

    // Documentation in subclasses because of synchro difference
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }
    /**
     * @since 1.8
     */
    AbstractStringBuilder append(AbstractStringBuilder asb) {
        if (asb == null)
            return appendNull();
        int len = asb.length();
        ensureCapacityInternal(count + len);
        asb.getChars(0, len, value, count);
        count += len;
        return this;
    }
    ....
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章