String、StringBuffer婿脸、StringBuilder之間的關(guān)系

在Java中,我們有三種存儲(chǔ)字符串的方式:String柄驻、StringBuffer狐树、StringBuilder。這篇文章主要是整理一下他們各自的優(yōu)缺點(diǎn)和使用場(chǎng)景鸿脓。該問題也是面試中常常被問到的基礎(chǔ)知識(shí)抑钟。

它們之間的關(guān)系圖如下:

image

1.三者區(qū)別

1.1 是否可變

String定義的字符串不可被改變。 每次對(duì)String對(duì)象進(jìn)行改變的時(shí)候野哭,其實(shí)是Java新創(chuàng)建了一個(gè)對(duì)象在塔,然后將之前的指針指向的新的對(duì)象。這樣做不僅浪費(fèi)了很多空間拨黔,還降低了效率蛔溃。
而StringBuilder和StringBuffer是可變對(duì)象。它們都繼承自AbstractStringBuilder類篱蝇,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串贺待。因此他們的類創(chuàng)建的字符串對(duì)象能夠被多次修改,而不產(chǎn)生新的未使用對(duì)象零截。他們倆可使用的方法也是相同的麸塞。

1.2 線程安全

StringBuilder是線程不安全的,StringBuffer是線程安全的涧衙。因此單線程下使用StringBuilder會(huì)效率更高哪工,多線程下使用StringBuffer會(huì)效率更高。操作小數(shù)據(jù)的話弧哎,還是String效率高雁比。

1.3 應(yīng)用場(chǎng)景

String使用場(chǎng)景:

  • 字符串內(nèi)容不長發(fā)生改變的業(yè)務(wù)場(chǎng)景
  • 比如:常量聲明、少量字符串拼接

StringBuffer應(yīng)用場(chǎng)景:

  • 頻繁進(jìn)行字符串運(yùn)算時(shí)(拼接傻铣、替換章贞、刪除)
  • 多線程時(shí)、因?yàn)樗С志€程安全
  • 比如:XML解析非洲、HTTP參數(shù)的解析與封裝

StringBuilder應(yīng)用場(chǎng)景:

  • 頻繁進(jìn)行字符串運(yùn)算時(shí)(拼接鸭限、替換、刪除)
  • 單線程時(shí)两踏,因?yàn)樗恢С志€程安全
  • 比如:SQL語句拼接败京、Json數(shù)據(jù)封裝

2.StringBuffer

了解StringBuffer之前,我們先回顧一下String的特點(diǎn)梦染,String字符串一旦定義就不能修改也不能擴(kuò)充的赡麦,而且朴皆,當(dāng)使用連接符對(duì)字符串進(jìn)行拼接的時(shí)候java會(huì)為字符串新開辟空間,這樣就造成了空間的浪費(fèi)泛粹。

為此StringBuffer作為解決方案應(yīng)運(yùn)而生遂铡,他是線程安全的可變字符序列。他是一個(gè)用final修飾的類晶姊,它繼承于Object扒接,實(shí)現(xiàn)了兩個(gè)接口。該接口定義后內(nèi)容可變们衙,大小可變钾怔,使用拼接不會(huì)產(chǎn)生新的空間。他就類似于一個(gè)字符串的緩沖區(qū)蒙挑。

2.1 容量和長度

StringBuffer有兩個(gè)屬性宗侦,一個(gè)是容量,一個(gè)是當(dāng)前長度忆蚀。容量代表的是能容納多大的字符串矾利,默認(rèn)是16個(gè)字符大小。

2.2 構(gòu)造方法

它有三個(gè)構(gòu)造方法蜓谋,一個(gè)是無參的(最常用)梦皮,一個(gè)是傳入整型參數(shù)的,用于指定容量桃焕,指定了多少剑肯,容量就變成多少。一個(gè)是字符串參數(shù)的观堂,用于指定內(nèi)容让网,容量是16+參數(shù)的長度。

new StringBuffer(); //容量為16
new StringBuffer(int capacity); //容量是int
new StringBuffer(String str);   //容量是str.length()+16

2.3 常用方法

  • append:追加

可以將任意的類型的數(shù)據(jù)添加到字符串的緩沖區(qū)师痕,返回值是StringBuffer溃睹,就是它緩沖區(qū)本身。

StringBuffer sb = new StringBuffer();
StringBuffer sb1 = sb.append("hello");
System.out.println(sb); //輸出hello
System.out.println(sb1); //輸出hello
System.out.println(sb == sb1); //輸出true

因此胰坟,直接sb.append()即可因篇,無需使用引用進(jìn)行接收。

StringBuffer sb = new StringBuffer();
sb.append(true).append(123).append("heihei");   //鏈?zhǔn)骄幊?System.out.println(sb);                         //輸出true123heihei
  • insert:插入

此方法可指定位置插入任意類型數(shù)據(jù)笔横。從0開始計(jì)數(shù)竞滓。

sb.insert(5,"world");
  • deleteCharAt:刪除指定位置的一個(gè)字符
public StringBuffer deleteCharAt(int index);
  • delete(int start, int end ):刪除指定長度字符串
public StringBuffer delete(int start, int end);
  • replace(int start, int end, String str):替換指定位置、長度字符串
public StringBuffer replace(int start, int end, String str);
  • reverse():翻轉(zhuǎn)
public StringBuffer reverse();
  • 字符串截取
public String substring(int start); //從start開始截取直到最后
pubic String substring(int start, int end); //從start截取吹缔,到end結(jié)束

注意返回的是字符串

2.4 String到StringBuffer的轉(zhuǎn)換

錯(cuò)誤轉(zhuǎn)換方式:

StringBuffer sb = "hello";
Stringbuffer sb = s;

正確的方式:

StringBuffer sb = new StringBuffer(s);
StringBuffer sb1 = new Stringbuffer();
sb1.append(s)

2.5 StringBuffer到String的轉(zhuǎn)換

1.通過構(gòu)造方法

String str = new String(buffer)

2.通過toString()

String str = buffer.toString()

任何引用類型調(diào)用toString都可以轉(zhuǎn)換成字符串商佑。

2.6 String與StringBuffer作為形參傳遞的不同

對(duì)于基本數(shù)據(jù)類型來說,形參的改變不影響實(shí)參厢塘,但是對(duì)于引用數(shù)據(jù)類型來說茶没,形參的改變直接改變了實(shí)際的參數(shù)肌幽。

但是字符串雖然是引用類型,但他是比較特殊的抓半,因?yàn)樗浅A课辜保鎯?chǔ)在字符串常量池中。是一種特殊的引用類型笛求,我們可以將它是為基本數(shù)據(jù)類型煮岁,所以當(dāng)字符串作為形參的時(shí)候,形參改變但實(shí)參是不改變的涣易。

StringBuffer是正常的引用類型,形參改變則實(shí)參改變冶伞。

3.可變?cè)?/h2>

StringBuffer(始于 JDK 1.0 )和StringBuilder(始于 JDK 1.5)都是為了提高字符串的拼接效率新症,直接使用String的+進(jìn)行拼接的話JVM會(huì)創(chuàng)建多個(gè)字符串對(duì)象,造成開銷浪費(fèi)响禽。他倆用法一樣徒爹,只不過Buffer是線程安全,Builder是線程不安全的芋类。

String源碼中有一個(gè)成員是隆嗅,使用了final修飾,意思是不能更改:

private final char value[];

而Buffer和Builder的成員同樣也是一個(gè)字符數(shù)組侯繁,但是沒有使用final修飾:

char value[];

所以這就是可變和不可變的基礎(chǔ)和前提胖喳。

當(dāng)要存入字符串的長度+value的長度-value的長度>0的時(shí)候,說明贮竟,此時(shí)的容量已經(jīng)不足以裝下新的字符串了丽焊。然后Java會(huì)將原來的字符數(shù)組復(fù)制一份(使用的是str.getchars()),然后開辟一個(gè)新的數(shù)組咕别,賦予新的容量技健,該容量是str.length()+value,最后return this惰拱,返回當(dāng)前對(duì)象雌贱。返回當(dāng)前對(duì)象的好處就是可以寫成鏈?zhǔn)骄幊獭?br> String只要已添加就去開辟新對(duì)象,而Buffer和Builder只有在容量不夠的時(shí)候才去開辟新對(duì)象偿短。

4.注意事項(xiàng)

StringBuilder sb1 = new StringBuilder("abc");
StringBuilder sb2 = new StringBuilder("abc");

System.out.println(sb1 == sb2);//false
System.out.println(sb1.equals(sb2));//false

第一個(gè)返回的是false是因?yàn)樗容^的是對(duì)象的地址值欣孤,而第二個(gè)返回的是false是因?yàn)镾tringBuilder沒有重寫equals方法,使用的是Object的比較方式翔冀,也就是比較地址值导街。所以,要想用值來比較纤子,應(yīng)該重寫equals方法搬瑰。

String str1 = "abc";
StringBuilder sb1 = new StringBuilder("abc");
System.out.println(str1.equals(sb1));//false

雖然string重寫了equals方法款票,但是,sb1對(duì)象不是String類的實(shí)例泽论,所以返回的也是false.

參考:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艾少,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子翼悴,更是在濱河造成了極大的恐慌缚够,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹦赎,死亡現(xiàn)場(chǎng)離奇詭異谍椅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)古话,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門雏吭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人陪踩,你說我怎么就攤上這事杖们。” “怎么了肩狂?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵摘完,是天一觀的道長。 經(jīng)常有香客問我傻谁,道長孝治,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任审磁,我火速辦了婚禮荆秦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘力图。我一直安慰自己步绸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布吃媒。 她就那樣靜靜地躺著瓤介,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赘那。 梳的紋絲不亂的頭發(fā)上刑桑,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音募舟,去河邊找鬼祠斧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拱礁,可吹牛的內(nèi)容都是我干的琢锋。 我是一名探鬼主播辕漂,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼吴超!你這毒婦竟也來了钉嘹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤鲸阻,失蹤者是張志新(化名)和其女友劉穎跋涣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸟悴,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陈辱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了细诸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片性置。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖揍堰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嗅义,我是刑警寧澤屏歹,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站之碗,受9級(jí)特大地震影響蝙眶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褪那,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一幽纷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧博敬,春花似錦友浸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至祭往,卻和暖如春伦意,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背硼补。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工驮肉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人已骇。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓离钝,卻偏偏與公主長得像票编,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子奈辰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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