今天很大家來聊一下這個(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è)對象被更改了塌西,在后面加上了一段新的字符他挎,但這只是假象,因?yàn)槲覀儎偛耪f過String類型的字符串長度是不可變的啊捡需,其實(shí)JVM是先創(chuàng)建的了一個(gè)str對象办桨,將“abc”賦值給str,然后在內(nèi)存中又創(chuàng)建了第二個(gè)str對象站辉,將第一個(gè)str對象中的“abc”與”de“相加再賦值給第二個(gè)str對象呢撞,此時(shí)Java虛擬機(jī)的垃圾回收機(jī)制開始其工作將第一個(gè)str對象回收损姜。所以說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)鍵字是給線程加鎖比规,枷鎖是會帶來性能上的損耗的,故用SringBuilder 比 StringBuffer 要快
鎖不懂先沒關(guān)系拦英,往下看蜒什!暫且理解為什么快。
三.SringBuilder 線程不安全 和 StringBuffer線程安全
? 線程安全不同的問題要和剛才的的思路連起來疤估,正是因?yàn)橛辛藅oStringCache關(guān)鍵字修飾StringBuffer的append方法有灾常,給線程加了鎖加了鎖所以線程安全。
? 這樣理解铃拇,如果一個(gè)StringBuffer對象的字符串在字符串緩沖區(qū)被多個(gè)線程同時(shí)使用時(shí)钞瀑,也就是多個(gè)線程同時(shí)操作,這樣會有出現(xiàn)錯(cuò)誤操作的概率锚贱,為了保證線程的安全性仔戈,進(jìn)行加鎖,這樣會使同一時(shí)間只有一個(gè)線程獲得權(quán)限拧廊,其他線程必須等待該線程結(jié)束并釋放鎖才能獲得權(quán)限监徘,這樣線程非常安全,雖然效率慢了點(diǎn)吧碾,但是當(dāng)項(xiàng)目安全性要求很高時(shí)就必須用StringBuffer凰盔。單一線程下還是的用更快一點(diǎn)的SringBuilder 。