2019-08-20

淺談String、StringBuffer 、StringBuilder和StringJoiner

可變性

String 類中使用 final 關(guān)鍵字修飾字符數(shù)組來保存字符串,private final char value[],所以 String 對象是不可變的。而StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在 AbstractStringBuilder 中使用字符數(shù)組保存字符串char[] value, 沒有用 final 關(guān)鍵字修飾,所以這兩種對象都是可變的。

安全性

String 中的對象是不可變的,線程安全。
StringBuffer 對方法加了同步鎖或者對調(diào)用的方法加 了同步鎖,所以是線程安全的。
下面是StringBuffer 源碼中的部分代碼:

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

StringBuilder 可變,但是沒有對方法加同步鎖,所以是非線程安全的。

性能

每次對 String 類型進(jìn)行改變的時候,都會生成一個新的 String 對象,然后將指針指向新的 String 對象。StringBuffer 與StringBuilder 每次都是對對象本身進(jìn)行操作,而不是生成新的對象并改變對象引用。相同情況下使用 StringBuilder 相比使用 StringBuffer 能獲得 10%~15% 左右的性能提升,但卻有多線程不安全的風(fēng)險。

對于三者使用的總結(jié)

操作少量的數(shù)據(jù): 適用String
單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuilder
多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuffer

AbstractStringBuilder 擴(kuò)容機(jī)制

由于StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,所以就來簡單的探討一下StringBuilder的擴(kuò)容機(jī)制,StringBuffer 只需在此基礎(chǔ)上加上同步鎖就是。
下面我們在源碼中分析:

public StringBuilder() {
        super(16);
    }
public StringBuilder(int capacity) {
        super(capacity);
    }
public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
 public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

從上面StringBuilder的構(gòu)造方法可以看出默認(rèn)容量為16,可以傳入?yún)?shù)(CharSequence為可讀可寫序列,意思還可以傳一個StringBuilder等的變量)。

   /*
     AbstractStringBuilder 中成員變量
   */
    char[] value;//StringBuilder本質(zhì)就是可變長度的字符數(shù)組
    int count;//已有內(nèi)容的長度
/*
這個方法保證minimumCapacity > 0
*/
 public void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > 0)
            ensureCapacityInternal(minimumCapacity);
    }

/*
這個方法就是獲得一個長度較大的字符數(shù)組
*/
  private void ensureCapacityInternal(int minimumCapacity) {
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

/*
這個方法就是獲取value新的值max(value.length*2+2,minimumCapacity)
*/
 private int newCapacity(int minCapacity) {
        int newCapacity = (value.length << 1) + 2;//左移一位,擴(kuò)大兩倍
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }


/*
獲取容量的最大值,防止內(nèi)存溢出
*/
private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // 內(nèi)存溢出
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

對于大數(shù)據(jù)的2進(jìn)制運(yùn)算,位移運(yùn)算符比那些普通運(yùn)算符的運(yùn)算要快很多,因?yàn)槌绦騼H僅移動一下而已,不去計算,這樣提高了效率,節(jié)省了資源

這里簡單說說StringJoiner

StringJoiner(JDK1.8),在源碼中可以看到,內(nèi)部其實(shí)運(yùn)用的是StringBuilder ,感覺就是在StringBuilder 的基礎(chǔ)上可以快速拼接字符串。

public final class StringJoiner {
    private final String prefix;//開頭使用的字符序列 
    private final String delimiter;//要添加到每個元素之間的間隔符
    private final String suffix;// 最后使用的字符序列
    private StringBuilder value;//內(nèi)部運(yùn)用StringBuilder 
}
/*
添加內(nèi)容是調(diào)用StringBuilder的append()添加方法
*/
public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }
/*
返回一個StringBuilder的值
*/
 private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);//若為null就new StringBuilder()
        }
        return value;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、基礎(chǔ)知識:1、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機(jī)...
    殺小賊閱讀 2,573評論 0 4
  • 《Java從小白到大?!芳堎|(zhì)版已經(jīng)上架了?。?! 由字符組成的一串字符序列,稱為“字符串”,在前面的章節(jié)中也多次用到...
    tony關(guān)東升閱讀 1,297評論 0 2
  • 從網(wǎng)上復(fù)制的,看別人的比較全面,自己搬過來,方便以后查找。原鏈接:https://www.cnblogs.com/...
    lxtyp閱讀 1,439評論 0 9
  • 本文是我自己在秋招復(fù)習(xí)時的讀書筆記,整理的知識點(diǎn),也是為了防止忘記,尊重勞動成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 966評論 1 6
  • 面向?qū)ο蟮娜齻€特征 封裝,繼承,多態(tài).這個應(yīng)該是人人皆知.有時候也會加上抽象. 多態(tài)的好處 允許不同類對象對同一消...
    Blizzard_liu閱讀 1,837評論 0 6

友情鏈接更多精彩內(nèi)容