今天很大家來聊一下這個(gè)基礎(chǔ)的問題
說他們?nèi)咧g的區(qū)別我總結(jié)為一下三點(diǎn):
1.String長度不可變而StringBuffer和SringBuilder長度可變
2.他們的運(yùn)行速度不同 :SringBuilder > StringBuffer > String
3.SringBuilder 線程不安全 和 StringBuffer線程安全
下面我來一個(gè)一個(gè)解釋:
一.String長度不可變而StringBuffer和SringBuilder長度可變
廢話不多說,先上源碼!
如果你可以打開三個(gè)類的源碼看一下你就明白了




我們能看到,String這個(gè)類底層使用了final修飾的長度不可變的字符數(shù)組,所以它長度不可變
private final char value[];
而StringBuffer和StringBuilder 都繼承自AbstractStringBuilder ,且AbstractStringBuilder底層使用的是可變字符數(shù)組,所以二者長度可變。
char[] value;
二.他們的運(yùn)行速度不同 :SringBuilder > StringBuffer > String
先來看這樣一段代碼
public class MainTest {
public static void main(String[] args) {
String str = "abc";
System.out.println(str);
str = str + "cd";
System.out.println(str);
}
}
輸出結(jié)果為:
abc
abcd
? 整個(gè)程序運(yùn)行完我們看似是str這個(gè)對(duì)象被更改了,在后面加上了一段新的字符,但這只是假象,因?yàn)槲覀儎偛耪f過String類型的字符串長度是不可變的啊,其實(shí)JVM是先創(chuàng)建的了一個(gè)str對(duì)象,將“abc”賦值給str,然后在內(nèi)存中又創(chuàng)建了第二個(gè)str對(duì)象,將第一個(gè)str對(duì)象中的“abc”與”de“相加再賦值給第二個(gè)str對(duì)象,此時(shí)Java虛擬機(jī)的垃圾回收機(jī)制開始其工作將第一個(gè)str對(duì)象回收。所以說String類型的字符串要完成這樣”改變長度“的操作需要不斷地創(chuàng)建再回收,創(chuàng)建再回收,無形中經(jīng)過了很多步驟,而 StringBuffer和SringBuilder數(shù)組可變,直接可進(jìn)行更改,所以要更快。
而SringBuilder 為什么比 StringBuffer 要快呢?
先來看源碼:


? 從圖中可以看出StringBuffer的append的方法都被toStringCache關(guān)鍵字修飾了(不止圖中這兩個(gè)append方法包括StringBuffer源碼中所有append重載方法都被toStringCache修飾了。)
toStringCache關(guān)鍵字是給線程加鎖,枷鎖是會(huì)帶來性能上的損耗的,故用SringBuilder 比 StringBuffer 要快
鎖不懂先沒關(guān)系,往下看!暫且理解為什么快。
三.SringBuilder 線程不安全 和 StringBuffer線程安全
? 線程安全不同的問題要和剛才的的思路連起來,正是因?yàn)橛辛藅oStringCache關(guān)鍵字修飾StringBuffer的append方法有,給線程加了鎖加了鎖所以線程安全。
? 這樣理解,如果一個(gè)StringBuffer對(duì)象的字符串在字符串緩沖區(qū)被多個(gè)線程同時(shí)使用時(shí),也就是多個(gè)線程同時(shí)操作,這樣會(huì)有出現(xiàn)錯(cuò)誤操作的概率,為了保證線程的安全性,進(jìn)行加鎖,這樣會(huì)使同一時(shí)間只有一個(gè)線程獲得權(quán)限,其他線程必須等待該線程結(jié)束并釋放鎖才能獲得權(quán)限,這樣線程非常安全,雖然效率慢了點(diǎn),但是當(dāng)項(xiàng)目安全性要求很高時(shí)就必須用StringBuffer。單一線程下還是的用更快一點(diǎn)的SringBuilder 。