天天看點

String和StringBuffer的差別詳談[轉帖]

  看到這篇文章對String和StringBuffer的差別說的和詳細,與大家分享一下:   String類用來表示那些建立後就不會再改變的字元串,它是immutable的。而StringBuffer類用來表示内容可變的字元串,并提供了修改底層字元串的方法。       當我們進行字元拼接時,請使用StringBuffer類而非String類,因為前者将比後者快上百倍。 的确,在程式的太多場合我們都會進行字元串拼接工作,簡單的代碼示例如下: String str="You are nice.";

str+="I love you so much."; 如果用StringBuffer類的話,代碼如下: StringBuffer str= new StringBuffer("You are nice.");

str.append("I love you so much.");         從表面看來String類隻用一個加号(+)便完成了字元串的拼接,而StringBuffer類卻要調用一個append()方法,是否實作起來更簡潔,更單純呢?其實不然,讓我們了解一下程式運作内部發生了哪些事情:         經編譯後程式的bytecode(位元組碼)展示出了實質:  在用String類對象直接拼接時,JVM會建立一個臨時的StringBuffer類對象,并調用其append()方法完成字元串的拼接,這是因為 String類是不可變的,拼接操作不得不使用StringBuffer類(并且--JVM會将"You are nice."和"I love you so much."建立為兩個新的String對象)。之後,再将這個臨時StringBuffer對象轉型為一個String,代價不菲!可見,在這一個簡單的一次拼接過程中,我們讓程式建立了四個對象:兩個待拼接的String,一個臨時StringBuffer,和最後将StringBuffer轉型成為的String--它當然不是最初的str了,這個引用的名稱沒變,但它指向了新的String對象。         而如果直接使用StringBuffer類,程式将隻産生兩個對象:最初的StringBuffer和拼接時的String("I love you so much."),也不再需要建立臨時的StringBuffer類對象而後還得将其轉換回String對象。         可以想象,當我們的字元串要被循環拼接若幹段時,用String類直接操作會帶來多少額外的系統開銷,生成多少無用的臨時StringBuffer對象,并處理多少次無謂的強制類型轉換哪。 ------------------------------ 記得以前在網上看到一篇關于java面試題的文章,裡面好像有個題就是關于String與StringBuffer的,具體的記不清了,大概内容如下: 請說出下面代碼塊存在的問題: String tmp = “”; for(int i=0;i<n;I++){     tmp +=”x”; } 當時網上有人隻是簡單的說了要改用StringBuffer,這個存在效率問題,而沒有進一步說明,其實我也很郁悶,是什麼效率問題呢?“顧名思義,StringBuffer之是以效率好,應該是它提供了緩存機制吧”,我想很多朋友是這樣想的吧,HOHO。 當昨天晚上讀到Effective java一書的時候,我才恍然大悟,原來String是一個支援非可變性的類,這種類的特點是狀态固定(不存在任何修改對象的方法),在該對象的生存周期内,它的值是永遠不變的(它是線程安全的),它們更容易設計、實作、使用,不易出錯,更加安全。 由于String類是支援非可變性的,是以,當執行tmp +=”x”的時候,實際上是另外建立了一個對象,而tmp原來指向的那個對象就成了垃圾(當它沒有其它引用的時候),這樣的話一個循環就會産生n多對象,可以相象記憶體的浪費,怕怕。   先看一下String類中substring方法的實作 public String substring(int beginIndex, int endIndex) {        if (beginIndex < 0) {            throw new StringIndexOutOfBoundsException(beginIndex);        }        if (endIndex > count) {            throw new StringIndexOutOfBoundsException(endIndex);        }        if (beginIndex > endIndex) {            throw new StringIndexOutOfBoundsException(endIndex - beginIndex);        }        return ((beginIndex == 0) && (endIndex == count)) ? this :            new String(offset + beginIndex, endIndex - beginIndex, value); } 從藍色部份可以看出,它是重新建立了一個新的對象,符合“支援非可變性”的原則,但這卻也顯示出了非可變類的真正惟一的缺點,就是“對于每一個不同的值都要求一個單獨的對象”。 那為什麼String要設計成非可變類呢?我覺得String是java中使用最為頻繁的一個類,隻有使其支援非可變性,才有可能避免一系列的問題,比如說: String a,b,c; a=”test”; b=a; c=b; processA(){     …….. } ProcessB(){     …….. } ProcessC(){     …….. } 當String支援非可變性的時候,它們的值很好确定,不管調用哪個方法,都互不影響,如果它不支援的話,那麼我無法想象其結果。 StringBuffer做為String的“配套類(companying class)”,它的作用就是為了解決上述問題的,StringBuffer扮演了String的可變配套類角色。非可變類本質上是線程安全的,它們不要求做同步處理,我們可以将其共享給所有使用者,讓所有的“用戶端程式員”都可以直接使用此類而不需要做任何額外的工作。

繼續閱讀