對String,StringBuilder,StringBuffer的理解

 平時我們一般涉及到字符串的拼接,最本能最直接的方法就是+.

String s1 = "Hello";
s1=s1+"word";

當數據拼接次數比較少的時候,這樣的方法無可厚非,但是一旦次數較多時,這樣的方法效率很低,而且浪費大量的空間

現在我要講的是String,StringBuilder,StringBuffer,這三個有什麼區別,以及平時我們使用時該注意什麼?

1.String

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

      爲什麼會浪費大量的空間?

             看上面的代碼,假設s1指向地址0x0001 ,當重新賦值後s1指向的地址是0x0002了,然而地址0x0001裏保存的s1依然存在,這就導致了每次重新賦值,就會產生一個新的地址指向,而原來的不會消失,浪費了大量的空間。因此String的操作都是改變賦值地址而不是改變值操作。 

2. StringBuffer

      StringBuffer是可變類和線程安全的字符串操作類,任何對它指向的字符串的操作都不會產生新的對象。 每個StringBuffer對象都有一定的緩衝區容量,當字符串大小沒有超過容量時,不會分配新的容量,當字符串大小超過容量時,會自動增加容量。

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
     public StringBuilder() {
        super(16);
     }


    /**
     * Constructs a string builder initialized to the contents of the
     * specified string. The initial capacity of the string builder is
     * {@code 16} plus the length of the string argument.
     *
     * @param   str   the initial contents of the buffer.
     */
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

       看上面的源碼我們會發現

        StringBuffer buf=new StringBuffer(); //分配長16字節的字符緩衝區 
        StringBuffer buf=new StringBuffer("this"); //分配長"this".length()+16字節的字符緩衝區 
        StringBuffer buf=new StringBuffer("this")//在緩衝區中存放了字符串,並在後面預留了16字節的空緩衝區。 

       那麼字符串大小超過容量時是怎麼擴容的呢?

         這可能就涉及到其常用的append方法了

    public StringBuilder append(StringBuffer sb) {
        super.append(sb);
        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;
    }

     /**
     * For positive values of {@code minimumCapacity}, this method
     * behaves like {@code ensureCapacity}, however it is never
     * synchronized.
     * If {@code minimumCapacity} is non positive due to numeric
     * overflow, this method throws {@code OutOfMemoryError}.
     */
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

     /**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by the same amount + 2 if
     * that suffices.
     * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
     * unless the given minimum capacity is greater than that.
     *
     * @param  minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero or
     *         greater than Integer.MAX_VALUE
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;(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;
    }

    看上面的源碼會發現擴容到原來的兩倍+2的長度,如果還是不夠的話就用到了minimumCapacity=count+len這個長度

 

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