而StringBuilder的toString方法的實現(xiàn)其實更簡單,源碼如下:
@Override
public String toString() { // Create a copy, don't share the array
return new String(value, 0, count);
}復(fù)制代碼
這里直接實例化了一個String對象并將StringBuilder中的value傳入,我們來看下String(value, 0, count)這個構(gòu)造方法:
public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset);
} if (count < 0) { throw new StringIndexOutOfBoundsException(count);
} // Note: offset or count might be near -1>>>1.
if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset count);
} this.value = Arrays.copyOfRange(value, offset, offset count);
}復(fù)制代碼
可以看到,在String的這個構(gòu)造方法中又通過Arrays.copyOfRange方法進行了數(shù)組拷貝,Arrays.copyOfRange的源碼如下:
public static char[] copyOfRange(char[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from " > " to); char[] copy = new char[newLength];
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength)); return copy;
}復(fù)制代碼
Arrays.copyOfRange與Arrays.copyOf類似,內(nèi)部都是重新實例化了一個char[]數(shù)組,所以String構(gòu)造方法中的this.value與傳入進來的value不是同一個對象。意味著StringBuilder在每次調(diào)用toString的時候生成的String對象內(nèi)部的char[]數(shù)組并不是同一個!這里立一個Falg!
3.StringBuilder的其它方法
StringBuilder除了提供了append方法、subString方法以及toString方法外還提供了還提供了插入(insert)、刪除(delete、deleteCharAt)、替換(replace)、查找(indexOf)以及反轉(zhuǎn)(reverse)等一些列的字符串操作的方法。但由于實現(xiàn)都非常簡單,這里就不再贅述了。
二、StringBuffer
在第一節(jié)已經(jīng)知道,StringBuilder的方法幾乎都是在它的父類AbstractStringBuilder中實現(xiàn)的。而StringBuffer同樣繼承了AbstractStringBuilder,這就意味著StringBuffer的功能其實跟StringBuilder并無太大差別。我們通過StringBuffer幾個方法來看
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache; @Override
public synchronized StringBuffer append(String str) {
toStringCache = null; super.append(str); return this;
} /**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
@Override
public synchronized StringBuffer delete(int start, int end) {
toStringCache = null; super.delete(start, end); return this;
} /**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
@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 substring(int start) { return substring(start, count);
}
// ...復(fù)制代碼
可以看到在StringBuffer的方法上都加上了synchronized關(guān)鍵字,也就是說StringBuffer的所有操作都是線程安全的。所以,在多線程操作字符串的情況下應(yīng)該首選StringBuffer。
另外,我們注意到在StringBuffer的方法中比StringBuilder多了一個toStringCache的成員變量 ,從源碼中看到toStringCache是一個char[]數(shù)組。它的注釋是這樣描述的:
toString返回的最后一個值的緩存,當(dāng)StringBuffer被修改的時候該值都會被清除。
我們再觀察一下StringBuffer中的方法,發(fā)現(xiàn)只要是操作過操作過StringBuffer中char[]數(shù)組的方法,toStringCache都被置空了!而沒有操作過字符數(shù)組的方法則沒有對其做置空操作。另外,注釋中還提到了 toString方法,那我們不妨來看一看StringBuffer中的 toString,源碼如下:
@Override
public synchronized String toString() { if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
} return new String(toStringCache, true);
}復(fù)制代碼
這個方法中首先判斷當(dāng)toStringCache 為null時會通過 Arrays.copyOfRange方法對其進行賦值,Arrays.copyOfRange方法上邊已經(jīng)分析過了,他會重新實例化一個char[]數(shù)組,并將原數(shù)組賦值到新數(shù)組中。這樣做有什么影響呢?細(xì)細(xì)思考一下不難發(fā)現(xiàn)在不修改StringBuffer的前提下,多次調(diào)用StringBuffer的toString方法,生成的String對象都共用了同一個字符數(shù)組–toStringCache。這里是StringBuffer和StringBuilder的一點區(qū)別。至于StringBuffer中為什么這么做其實并沒有很明確的原因,可以參考StackOverRun
《Why StringBuffer has a toStringCache while StringBuilder not?》中的一個回答:
1.因為StringBuffer已經(jīng)保證了線程安全,所以更容易實現(xiàn)緩存(StringBuilder線程不安全的情況下需要不斷同步toStringCache)
2.可能是歷史原因
三、 總結(jié)
本篇文章到此就結(jié)束了。《深入理解Java中的字符串》通過兩篇文章深入的分析了String、StringBuilder與StringBuffer三個字符串相關(guān)類。這塊內(nèi)容其實非常簡單,只要花一點時間去讀一下源碼就很容易理解。當(dāng)然,如果你沒看過此部分源碼相信這篇文章能夠幫助到你。不管怎樣,相信大家通過閱讀本文還是能有一些收獲。解了這些知識后可以幫助我們在開發(fā)中對字符串的選用做出更好的選擇。同時,這塊內(nèi)容也是面試???,相信大家讀完本文去應(yīng)對面試官的問題也會綽綽有余。
想了解更多編程學(xué)習(xí),敬請關(guān)注php培訓(xùn)欄目!
更多關(guān)于云服務(wù)器,域名注冊,虛擬主機的問題,請訪問西部數(shù)碼官網(wǎng):m.ps-sw.cn