天天看點

字元竄拼接方法 append() 源碼解析

本文通過StringBuffer 源碼,來了解append(),方法。

============================================================================

str.append(""); 是用來拼接字元竄,一般人我不告訴他。 

一、直接上示例:

public class TestString {

    public static void main(String[] args) {

       StringBuffer buffer = new StringBuffer();
       buffer.append("hello ");
       buffer.append("world!");
        System.out.println(buffer); //結果 hello world!
    }
}
           

二、斷點跟蹤:(以下都是jdk1.8源碼)

1、進入StringBuffer類的 append(String str) 方法: str = hello, 傳進來。

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
{
   @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
}
           

2、調用了父類的方法super.append():str=hello ,傳到父類的方法。

public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);  //count :存放的字元的長度 現在是0, len = 5
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
           

2.1、 進入 ensureCapacityInternal(),   判斷字元總長度有沒有超過 字元數組的容量值。

private void ensureCapacityInternal(int minimumCapacity) {     // 0+5
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {        //value.length 預設初始值為16
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }
           
注意區分下面兩者:
value.length   : 是 char[]  value 數組的 長度,預設初始值 16.
str.length()    :字元串的長度,(也可以了解為字元的個數)。
/**
     * Returns the length (character count).
     *
     * @return  the length of the sequence of characters currently
     *          represented by this object
     */
    @Override
    public int length() {
        return count;     //看看,傳回的count
    }
           

2.2、 當minimumcapacity > value.length,   字元數組開始擴容。

private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;    //容量擴大為 原來的2倍+2
        if (newCapacity - minCapacity < 0) {        //如果還是比字元總長度小, 那麼 總長度就設定為容量。
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    } 
           

3、進入String類的方法 getChars(srcBegin,srcEnd, char [] dest, int destBegin ); 

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);
    }
           

難點:

難點a、這裡可能會比較不太明白,  在進入抽象父類的方法後, 又調用了String類的getChar() 方法。

注意: str.getChar();  這裡的str 是是傳入 “hello”字元竄。 是以,其實這裡已經建立了一個String類,String str ="hello";

并且, String類,在内部定義了一個 字元數組,private final char[] value ;   字元串會被分解存放在這個數組裡面。是以  

“hello”, 被存儲為 char [] value = {"h","e","l","l","o"}。如果了解這裡的話, 進入< 3 > 方法的幾個參數就好了解了。

難點b、System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd-srcBegin);   

最後這個方法的參數值 : value,   到底代表的是那個類的 char[] 數組呢?  

因為 <3 >方法是在String類中調用的,   是以value 所指的是  String 類中維護的 那個  char [] value = {"h","e","l","l","o"}; 

參數解釋:

srcBegin:  複制源數組的開始位置(數組下标), 例如: 這裡srcBegin= 0 , 是以從 字元  h  開始複制。 

srcEnd :  源數組的結束位置, 這裡 srcEnd = len,   "hello"的長度。

char dst[] :  StringBuffer 存儲的字元數組。(StringBuffer 類一 維護了一個 字元數組  char value []), 因為命名都一樣,可能會有點搞混。

srcEnd -srcBegin:   要被複制的元素的個數。其實完全可以用  srcEnd 來表示就可以了。

4、最後進入System類的 方法 arraycopy();數組複制。

三、結論:

由此可以看出, StringBuffer拼接字元竄的 實質是:char類型數組的擴容複制。

============================================================================本文到此結束,後續内容繼續補充。

繼續閱讀