String被冒、StringBuffer和StringBuilder


閱讀java源碼的一些體會


一军掂、CharSequence接口

public interface CharSequence {
     int length();
     char charAt(int index);
     CharSequence subSequence(int start, int end);
     public String toString();
     public default IntStream chars() {……}
     public default IntStream codePoints() {……}
}

? ?default是java8的新特性,具體可以想見文檔昨悼,顯然此接口主要是保證有獲取內(nèi)容的公共接口蝗锥。還實現(xiàn)了轉(zhuǎn)換為IntStream的默認函數(shù)。

二率触、String類的一些感覺

1.結(jié)構(gòu)

  • 請看類的實現(xiàn):
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence{
    private fianl char value[];
    private int hash;
    private static final long serialVersionUID = -6849794470754667710L;
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
  /**省略實現(xiàn)細節(jié)
**/
}

? ?可以看到此時的結(jié)構(gòu)體一共有四個變量终议。扣除為了實現(xiàn)進程間傳遞的變量葱蝗。主要的變量就是存儲內(nèi)容value和hash穴张。其中value為其取值,而hash則是String的hash函數(shù)值两曼。
? ?這里可以看到String類型中的value變量是final類型的皂甘,是不可變的變量,同時String類型也沒有提供修改char[]數(shù)組的接口悼凑。這就可以肯定value在構(gòu)造之初之后就不能改變叮贩。這表示新的內(nèi)容產(chǎn)生新的對象。

2.常用代碼分析

 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);
        }
        //將內(nèi)容從value中復(fù)制到dst數(shù)組中佛析,arraycopy是native方法,這個方法顯
        //然可以有相當(dāng)強大的效率
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }
 public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
   public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
      //產(chǎn)生了新的對象哦
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
 public String trim() {
        int len = value.length;
        int st = 0;
        char[] val = value;    /* avoid getfield opcode */

        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
//還是產(chǎn)生了新對象哦
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

? ?此外,replace彪蓬、splite都和Pattern和matcher有關(guān)寸莫,將數(shù)組內(nèi)容替換,并返回新的對象档冬。

二膘茎、StringBuilder

1.結(jié)構(gòu)

  • 請看類的實現(xiàn):
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
 /** use serialVersionUID for interoperability */
    static final long serialVersionUID = 4383685877147921099L;
    …………
 @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}

? ?這里可以看到并沒有其他的變量,那么我們看其父類:

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;
   /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
  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;
    }
  …………
}

? ?其中這里有一段關(guān)于vlaue數(shù)組長度擴展的關(guān)鍵代碼:

  /**
     * This implements the expansion semantics of ensureCapacity with no
     * size check or synchronization.
     */
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

? ?綜上所述酷誓,我們可以看到披坏,StringBuilder直接調(diào)用AbstractStringBuilder的父接口,其append每次首先檢查char[]數(shù)組長度盐数,如果大小不夠棒拂,就重新擴充大小,并拷貝原來的數(shù)組內(nèi)容玫氢,可以說StringBuilder是緩存的String帚屉,因此效率更高。想reaplace漾峡、delete這些方法都是在緩存數(shù)組上操作攻旦,然后返回對象本身。但如果需要獲得String類型生逸,則還是會返回String類型的對象牢屋。

三且预、StringBuffer

1.結(jié)構(gòu)

  • 請看類的實現(xiàn)(通過我的read,方法都有synchronized烙无,是線程安全得):

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
 /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
    * 關(guān)鍵字代表此變量之存在于內(nèi)存中锋谐,而不能傳輸(例如持久化)
     */
    private transient char[] toStringCache;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    static final long serialVersionUID = 3388685877147921107L;
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }
…………
 @Override
    public synchronized void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > value.length) {
            expandCapacity(minimumCapacity);
        }
    }
}

2.關(guān)鍵代碼

  /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @see        #length()
     */
    @Override
    public synchronized void setCharAt(int index, char ch) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        toStringCache = null;
        value[index] = ch;
    }
    @Override
    public synchronized void setCharAt(int index, char ch) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        toStringCache = null;
        value[index] = ch;
    }
     @Override
      public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
  @Override
    public synchronized StringBuffer insert(int index, char[] str, int offset,
                                            int len)
    {
        toStringCache = null;
        super.insert(index, str, offset, len);
        return this;
    }
   @Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

? ?可以說StringBuffer是線程安全得,但是其他的核心代碼幾乎是StringBuilder的拷貝皱炉。顯然StringBuilder效率上要更好怀估,然而多線程下顯然是有危險的。

四合搅、總結(jié)

? ? StringBuffer和StringBuilder異同:

  • StringBuffer是線程安全得可變序列多搀,而StringBuilder是5.0新增的一個特性,用于和StringBuffer做兼容灾部,其不保證線程安全康铭,可以看到StringBuilder顯然要比StringBuffer快。
  • 為了保證快速的toString赌髓,StringBuffer提供了字符緩存數(shù)組从藤,顯然這時候非常快锁蠕。
  • String類每次改變都將產(chǎn)生新對象夷野。因而StringBuffer一般情況下要比String快。
  • System.arraycopy是native方法荣倾,顯然拷貝效率要更好悯搔,如果需要拷貝,可以 優(yōu)先考慮使用arraycopy拷貝普通數(shù)組舌仍。
  • default關(guān)鍵字主要用于擴展接口的同時避免修改集成樹妒貌,可以提供接口的默認實現(xiàn),transient保證變量在持久化的過程中智能待在內(nèi)存铸豁。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灌曙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子节芥,更是在濱河造成了極大的恐慌在刺,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件头镊,死亡現(xiàn)場離奇詭異增炭,居然都是意外死亡,警方通過查閱死者的電腦和手機拧晕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門隙姿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厂捞,你說我怎么就攤上這事输玷《铀浚” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵欲鹏,是天一觀的道長机久。 經(jīng)常有香客問我,道長赔嚎,這世上最難降的妖魔是什么膘盖? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮尤误,結(jié)果婚禮上侠畔,老公的妹妹穿的比我還像新娘。我一直安慰自己损晤,他們只是感情好软棺,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尤勋,像睡著了一般喘落。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上最冰,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天瘦棋,我揣著相機與錄音,去河邊找鬼暖哨。 笑死赌朋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鹿蜀。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼服球,長吁一口氣:“原來是場噩夢啊……” “哼茴恰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起斩熊,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤往枣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后粉渠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體分冈,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年霸株,在試婚紗的時候發(fā)現(xiàn)自己被綠了雕沉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡去件,死狀恐怖坡椒,靈堂內(nèi)的尸體忽然破棺而出扰路,到底是詐尸還是另有隱情,我是刑警寧澤倔叼,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布汗唱,位于F島的核電站,受9級特大地震影響丈攒,放射性物質(zhì)發(fā)生泄漏哩罪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一巡验、第九天 我趴在偏房一處隱蔽的房頂上張望际插。 院中可真熱鬧,春花似錦深碱、人聲如沸腹鹉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽功咒。三九已至,卻和暖如春绞蹦,著一層夾襖步出監(jiān)牢的瞬間力奋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工幽七, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留景殷,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓澡屡,卻偏偏與公主長得像猿挚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驶鹉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350

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