Java 基礎(chǔ) 之 String,StringBuilder, StringBuffer

在Java中字符串的使用非常廣泛,我們常用的如:String ,StringBuffer, StringBuilder.但是一直都沒有系統(tǒng)的整理過他們的區(qū)別,今天就系統(tǒng)的整理一下,記錄自己的學(xué)習(xí)歷程。

一:String


首先我們看下String的源碼:

public final class String implementsjava.io.Serializable, Comparable, CharSequence

從String的類聲明上就可以發(fā)現(xiàn),String是一個(gè)類而不是基本數(shù)據(jù)類型。

既然是一個(gè)類,那String的使用也很簡單,直接new就可以了。

String可以通過 “+ “來完成字符串的拼接,那我們來做個(gè)測(cè)試:

使用是很簡單,但是通過我們上面的測(cè)試發(fā)現(xiàn)一個(gè)問題就是,當(dāng)我們 給str + “test”后,他的hashCode發(fā)生了變化,說明了第10行的str已經(jīng)是一個(gè)新的對(duì)象了。

在String的源碼中維護(hù)了一個(gè)finalchar value[],如下:

private final charvalue[];

所以從源碼中我們可以發(fā)現(xiàn),value是final類型的,是不能被改變的,所以只要改變就只能生一個(gè)新的String對(duì)象。也可以說String類型的對(duì)象是長度不可變的,String拼接字符串每次都要生成一個(gè)新的對(duì)象,所以拼接字符串的效率也比較低。

二:StringBuffer


首先我們看下StringBuffer的源碼:

public final class StringBuffer extends AbstractStringBuilder

? ? ? ? ? ? ? ? ?implementsjava.io.Serializable, CharSequence

從源碼中我們可以看出,StringBuffer也是一個(gè)final class,也不能被繼承。既然是類,那使用也一樣直接new一個(gè)對(duì)象出來。

StringBuffer是通過.append 來完成字符串的拼接,那讓我們來做個(gè)測(cè)試

從我們的測(cè)試來看,StringBuffer和 String 類是不同的,因?yàn)镾tringBuffer被修改后并沒有產(chǎn)生新的對(duì)象,是在之前的對(duì)象上修改的。下面我們來看下部分源碼:

? ?publicStringBuffer() {

? ? ? super(16);

? ? ?}

? ??public StringBuffer append(CharSequence s) {

?????????if (s == null) s = "null";

???????? if (s instanceofString) return this.append((String)s);

???????? if (s instanceofStringBuffer) return this.append((StringBuffer)s);

? ? ? ? ? return this.append(s, 0, s.length());

?????}

?????public synchronized StringBuffer append(CharSequence s, int start, intend)

?????{

????????super.append(s, start, end);

??????? return this;

?????}

?從上面的代碼中可以看出來,StringBuffer的初始容量可以容納16個(gè)字符,當(dāng)該對(duì)象的實(shí)體存放的字符的長度大于16時(shí),實(shí)體容量就自動(dòng)增加。

StringBuffer的函數(shù)都是加了Synchronized關(guān)鍵字的,所以StringBuffer的方法是線程安全的,可以在多線程中使用。

總結(jié):

如果對(duì)字符串的改變少,使用String;

如果對(duì)字符串修改的較多或需要線程安全就用StringBuffer,

三:StringBuilder


首先我們看下StringBuilder的源碼:

public final class StringBuilder extends AbstractStringBuilder?

????????????????????????implements java.io.Serializable, CharSequence

從源碼中我們可以看出,StringBuilder和StringBuffer一樣,也是一個(gè)final class,也不能被繼承。既然是類,那使用也一樣直接new一個(gè)對(duì)象出來。

StringBuilder是通過.append 來完成字符串的拼接,那讓我們來做個(gè)測(cè)試

從上面的測(cè)試我門可以發(fā)現(xiàn)StringBuilder 類的對(duì)象能夠被多次的修改,并且不產(chǎn)生新對(duì)象。

下面我們來看下部分源碼:

?public StringBuilder(String str) {

?????????super(str.length() + 16);

?????????append(str);

????}

? ?private StringBuilder append(StringBuilder sb) {

?????????if (sb == null) returnappend("null");

?????????int len = sb.length();

?????????int newcount = count + len;

?????????if(newcount > value.length)

?????????????expandCapacity(newcount);

?????????sb.getChars(0, len, value, count);

?????????count = newcount;

?????????return this;

?????}

從源碼中我們可以發(fā)現(xiàn)它和StringBuffer 之間的最大不同在于StringBuilder 的方法不是線程安全的(不能同步訪問)。所以在單線程的環(huán)境下StringBuilder相較于StringBuffer 有速度優(yōu)勢(shì),因?yàn)樗恍枰鐾教幚怼?/p>

StringBuffer的默認(rèn)長度是16, StringBuilder的默認(rèn)長度是16+初始化傳入字符串的長度。

四:擴(kuò)容


下面是擴(kuò)容的源碼:

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

?}

當(dāng)我們對(duì)StringBuffer和StringBuilder進(jìn)行append的時(shí)候,會(huì)先判斷當(dāng)前的容量是否可以放下,如果長度不夠,就會(huì)調(diào)用expandCapacity來進(jìn)行擴(kuò)容

擴(kuò)容的計(jì)算公式:現(xiàn)在的長度*2 + 2;

如果我們擴(kuò)容后的長度(newCapacity)還是放不下(minimumCapacity)的長度那就直接把所需要的長度賦值給擴(kuò)容后的長度(newCapacity = minimumCapacity);

因?yàn)楫?dāng)int的最大值 + 1就會(huì)變成負(fù)數(shù),所以我們需要在擴(kuò)容完后驗(yàn)證,newCapacity的正確性防止內(nèi)存溢出,如果超過了int的最大長度,那么就把NewCapacity 設(shè)置成Integer.MAX_VALUE,

newCapacity = Integer.MAX_VALUE;

最后把原數(shù)組copy到擴(kuò)容后的數(shù)組中:

?value = Arrays.copyOf(value,newCapacity);

總結(jié):

? ? 當(dāng)需要頻繁的字符串拼接和刪除時(shí),建議使用StringBuffer或StringBuilder

? ? 在單線程的程序中,使用String或StringBuilder

? ? 在多線程的程序中,使用StringBuffer.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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