從鄙人學計算機語言開始,使用字元串就用的String,並沒有覺得有什麼不妥。直到最近開始學習JAVA處理大數據開始,才慢慢感受到了字元串的不同類操作的不同。在用戶體驗層面,如果不是遇到數據量巨大的情況,並不能感受到String和其他兩者的區別。但是對於計算機底層實現上來看,就完全不同。不知道從哪哪聽說過一句話,叫做一個好的程序猿應該關注底層的實現效率,不僅僅是完成其功能。所以我準備,總結一下這三大字元串類:String,StringBuffer,StringBuilder。

1,存儲方式的不同

要關注其底層實現,就應該看他們在內存中是如何存放的。三者都是屬於引用類,也就是說,都是需要實例化出對象的。這麼說的時候我又有點心虛,因為String類是一類很奇怪的類,雖然Java的API將其歸類於引用類,但是引用類的存放規則是,在棧中有一個變數名,中間存放著該對象在堆中的引用。我們用示例來說明一下:

//實例化三個字元串
String st=new String("");
StringBuffer sb1=new StringBuffer("");
StringBuilder sb2=new StringBuilder("");

(內心吐槽一下我的sb取名方式)

new關鍵字就像一個標誌,凡是用new這個關鍵字new出來的對象,一定是放在堆中的,並且棧中有一個指向該對象的變數名,也就是我們所說的引用。但是String還有其他的構造方式。我們經常會見到

String s="acd";//s輸出為acd
String s1="acd"+"fr"+"fefj"//s1輸出為acdfrfefj
String s2="acd"+"frfefj";//s1輸出為acdfrfefj
System.out.println(s1==s2);//true
String s3=new String("frfefj");//s2輸出為frfefj
String s4=s+s3;//s3輸出為acdfrfefj
System.out.println(s1==s3)//false

我們看看在內存中他們是怎麼存放的

可以看出,String是一個很神奇的類,介於基礎類和引用類中間,具體和哪個類的性質相似則取決於其構造方法。而StringBuffer和StringBuilder則是普通的引用類,所有構造,存放均與其它引用類一樣。另外S停還有一處特別的地方在於String類是由final修飾詞修飾的,意味著,當String作為引用類時,初始化後是不可變化的。最開始我不能理解,明明可以有這種操作呀!

String s=new String("adc");
s=s+"d";

這不是可以變化的么?還是那個問題,String類在用戶體驗時並不能感受她的特別,但是在內存中就一目了然了。請看圖!噔噔噔噔

這裡的s其實已經指向另外一個new出來的對象了,只是源程序中沒有使用new而已。說明並不是在原對象上修改。

對於StringBuffer和StringBuilder來說,這一步驟在內存中是怎麼實現的呢?

StringBuffer sb=new StringBuffer("abd");
sb=sb.append("d");

這就是String和其他兩個方法的不同之處。那麼StringBuffer和StringBuilder又有什麼各自的神通呢?

2.StringBuffer與StringBuilder

兩者均繼承自公共的父類AbstractStringBuilder

StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的,源代碼如下:

public synchronized StringBuffer reverse() {
2 super.reverse();
3 return this;
4 }
5
6 public int indexOf(String str) {
7 return indexOf(str, 0); //存在 public synchronized int indexOf(String str, int fromIndex) 方法
8 }

線程安全在多線程編程中是一件很重要的事情。當你在一個線程中對一串字元串操作到一半的時候,咔擦,虛擬機將你的步驟剪短,提醒你,時間到了,該讓位給別人了,這時候如果接任操作的線程也對這串字元串進行操作。那麼可想而知就會出現錯誤了,鎖就是將這個字元串給鎖起來,沒有完成操作前不可以對這串字元串進行操作。也就保障了多線程同時運行時的線程安全問題。

StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。那麼為什麼還要有StringBuilder的類呢?在我看來,每實現一個功能都代表著擴展程序,也就是說在運行時花費的時間更多。尤其是StringBuffer與StringBuilder常常用於處理字元串量大的情況,影響也就比較大。因此在單線程程序中,推薦使用StringBuilder,在多線程中使用StringBuffer。在字元串少的情況下,推薦使用String類。

每一個類的存在都好有意義啊!都是為了應對不同的情況。對於字元串的操作,String類很厲害,有各種各樣的實現功能。有時間的話,可以考慮匯總一下。今天的博客就這麼收尾了。期待下次早點看見你來逛知乎,小提莫


推薦閱讀:
相关文章