Java StringBuffer和StringBuilder

作者:ouyangyewei
個人站點(diǎn):http://ouyangyewei.me/


簡介

StringBuffer和StringBuilder,兩者都是可變對象,都繼承java.lang.AbstractStringBuilder類,都實(shí)現(xiàn)java.io.Serializable和java.lang.CharSequence接口。
最大的區(qū)別在于:<b><u>StringBuffer是線程安全的,而StringBuilder是非線程安全的</u></b>

下面代碼摘自java.lang.StringBuffer

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

下面代碼摘自java.lang.StringBuilder

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

AbstractStringBuilder類

AbstractStringBuilder類封裝了StringBuffer和StringBuilder大部分操作的實(shí)現(xiàn)。

字符串的內(nèi)存形態(tài)

下面代碼摘自java.lang.AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;

StringBuffer和StringBuilder沒有具體的成員變量來存儲字符串,而是使用繼承自AbstractStringBuilder類的成員變量char[] value,因為沒有使用final關(guān)鍵字修飾,因此值是可變的。

字符串構(gòu)造方法

下面代碼摘自java.lang.StringBuffer

public StringBuffer() {
    super(16);
}

下面代碼摘自java.lang.StringBuilder

public StringBuilder() {
    super(16);
}

下面代碼摘自java.lang.AbstractStringBuilder

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

當(dāng)創(chuàng)建一個StirngBuffer或StringBuilder對象時,若不指定容量,則默認(rèn)創(chuàng)建長度為16的char類型數(shù)組

字符串的append操作

下面代碼摘自java.lang.AbstractStringBuilder,以入?yún)镾tring對象為例

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    // 檢查是否char[]數(shù)組是否需要擴(kuò)容
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    // value.length默認(rèn)長度是16
    // minimumCapacity = str.length + 字符串的實(shí)際長度
    // 若當(dāng)前字符串?dāng)?shù)組長度不足最小應(yīng)分配的長度,則將重新創(chuàng)建一個長度的char[]數(shù)組
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}
StringBuffer.append()
StringBuffer.append()

字符串的insert操作

下面代碼摘自java.lang.AbstractStringBuilder,以入?yún)镾tring對象為例

public AbstractStringBuilder insert(int offset, String str) {
    if ((offset < 0) || (offset > length()))
        throw new StringIndexOutOfBoundsException(offset);
    if (str == null)
        str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    System.arraycopy(value, offset, value, offset + len, count - offset);
    str.getChars(value, offset);
    count += len;
    return this;
}
StringBuffer.insert
StringBuffer.insert

假設(shè)執(zhí)行如下代碼:

StringBuffer sb = new StringBuffer("abghij");
sb.insert(2, "cdef");
StringBuffer.insert.visio
StringBuffer.insert.visio

字符串的delete操作

下面代碼摘自java.lang.AbstractStringBuilder

public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}

實(shí)際上的操作是字符串?dāng)?shù)組拷貝,假設(shè)執(zhí)行如下代碼:

StringBuffer sb = new StringBuffer("abcdefghij");
sb.delete(2, 6);
StringBuffer.delete
StringBuffer.delete

StringBuffer類

為什么是線程安全的

線程安全是指多線程操作同一個對象,不會出現(xiàn)同步等問題。StringBuffer類中,使用了大量的synchronized關(guān)鍵字來修飾方法。
摘取java.lang.StringBuffer部分使用synchronized關(guān)鍵字修飾的代碼

@Override
public synchronized int length() {
    return count;
}

@Override
public synchronized int capacity() {
    return value.length;
}

@Override
public synchronized void ensureCapacity(int minimumCapacity) {
    super.ensureCapacity(minimumCapacity);
}

transient關(guān)鍵字

摘自Java Language Specification, Java SE 7 Edition, Section 8.3.1.3. transient Fields

Variables may be marked transient to indicate that they are not part of the persistent state of an object.

在Java中,transient關(guān)鍵字用來指出哪些成員變量不應(yīng)該被序列化。值得注意的是:

  • 序列化針對的是對象,而不是類;
  • static修飾的變量,本身是隱式的transient,同時靜態(tài)變量是屬于類層次,不能被序列化;
  • transient只能用于修飾成員變量,不能修飾本地變量,不能修飾方法和類。

StringBuffer類中,有一個成員變量

/**
 * A cache of the last value returned by toString. Cleared
 * whenever the StringBuffer is modified.
 */
private transient char[] toStringCache;

toStringCache這個成員變量,從命名上看,猜測是為了用于toString()方法而做的字符串緩沖。可見,如果是為了做緩沖,確實(shí)沒必要在StringBuffer對象中持久化。

toString的操作

下面代碼摘自java.lang.StringBuffer

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

toStringCache獲得實(shí)際長度的字符串?dāng)?shù)組,并創(chuàng)建一個String對象


參考材料

Java SE java.lang.StringBuffer
Java SE java.lang.StringBuilder
Java transient關(guān)鍵字

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容