String , StringBuffer 和 StringBuilder 区别
轉載:http://www.blogjava.net/chenpengyi/archive/2006/05/04/44492.html
相信大家對?String?和?StringBuffer?的區別也已經很了解了,但是估計還是會有很多同志對這兩個類的工作原理有些不清楚的地方,今天我在這里重新把這個概念給大家復習一下,順便牽出?J2SE 5.0?里面帶來的一個新的字符操作的類——?StringBuilder?(先別忙著扔我磚頭,我還算清醒,我這里說的不是?C?#,?Java?也有?StringBuilder?類)。那么這個?StringBuilder?和?StringBuffer?以及我們最早遇見的?String?類有那些區別呢?在不同的場合下我們應該用哪個呢?我講講自己對這幾個類的一點看法,也希望大家提出意見,每個人都有錯的地方,在錯了改的同時更是一個學習的好機會。
???????簡要的說,?String?類型和?StringBuffer?類型的主要性能區別其實在于?String?是不可變的對象(為什么?問問?Java?的設計者吧,為什么?String?不是原生類型呢?)因此在每次對?String?類型進行改變的時候其實都等同于生成了一個新的?String?對象,然后將指針指向新的?String?對象,所以經常改變內容的字符串最好不要用?String?,因為每次生成對象都會對系統性能產生影響,特別當內存中無引用對象多了以后,?JVM?的?GC?就會開始工作,那速度是一定會相當慢的。這里嘗試舉個不是很恰當的例子:
???????String S1 = “abc”;
???????For(int I = 0 ; I < 10000 ; I ++)??// For?模擬程序的多次調用
???????{
??????????????S1 + = “def”;
??????????????S1 = “abc”;
}
如果是這樣的話,到這個?for?循環完畢后,如果內存中的對象沒有被?GC?清理掉的話,內存中一共有?上?萬個了,驚人的數目,而如果這是一個很多人使用的系統,這樣的數目就不算很多了,所以大家使用的時候一定要小心。
而如果是使用?StringBuffer?類則結果就不一樣了,每次結果都會對?StringBuffer?對象本身進行操作,而不是生成新的對象,再改變對象引用。所以在一般情況下我們推薦使用StringBuffer?,特別是字符串對象經常改變的情況下。而在某些特別情況下,?String?對象的字符串拼接其實是被?JVM?解釋成了?StringBuffer?對象的拼接,所以這些時候?String?對象的速度并不會比?StringBuffer?對象慢,而特別是以下的字符串對象生成中,?String?效率是遠要比?StringBuffer?快的:
???????String S1 = “This is only a” + “ simple” + “ test”;
???????StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
???????你會很驚訝的發現,生成?String S1?對象的速度簡直太快了,而這個時候?StringBuffer?居然速度上根本一點都不占優勢。其實這是?JVM?的一個把戲,在?JVM?眼里,這個
???????String S1 = “This is only a” + “ simple” + “test”;?其實就是:
???????String S1 = “This is only a simple test”;?所以當然不需要太多的時間了。但大家這里要注意的是,如果你的字符串是來自另外的?String?對象的話,速度就沒那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
這時候?JVM?會規規矩矩的按照原來的方式去做,?S1?對象的生成速度就不像剛才那么快了,一會兒我們可以來個測試作個驗證。
由此我們得到第一步結論:
在大部分情況下?StringBuffer > String
???????而?StringBuilder?跟他們比又怎么樣呢?先簡單介紹一下,?StringBuilder?是?JDK5.0?中新增加的一個類,它跟?StringBuffer?的區別看下面的介紹(來源?JavaWorld?):
???????Java.lang.StringBuffer?線程安全的可變字符序列。類似于?String?的字符串緩沖區,但不能修改。可將字符串緩沖區安全地用于多個線程。可以在必要時對這些方法進行同步,因此任意特定實例上的所有操作就好像是以串行順序發生的,該順序與所涉及的每個線程進行的方法調用順序一致。
???????每個字符串緩沖區都有一定的容量。只要字符串緩沖區所包含的字符序列的長度沒有超出此容量,就無需分配新的內部緩沖區數組。如果內部緩沖區溢出,則此容量自動增大。從?JDK 5.0?開始,為該類增添了一個單個線程使用的等價類,即?StringBuilder?。與該類相比,通常應該優先使用?StringBuilder?類,因為它支持所有相同的操作,但由于它不執行同步,所以速度更快。
但是如果將?StringBuilder?的實例用于多個線程是不安全的。需要這樣的同步,則建議使用?StringBuffer?。
這樣說估計大家都能明白他們之間的區別了,那么下面我們再做一個一般性推導:
在大部分情況下?StringBuilder > StringBuffer
因此,根據這個不等式的傳遞定理:?在大部分情況下
StringBuilder > StringBuffer > String
既然有這樣的推導結果了,我們做個測試驗證一下:
測試代碼如下:
| public class testssb { ??? ????/** Creates a new instance of testssb */ ????final static int ttime = 10000;//?測試循環次數 ????public testssb() { ????} ??? ????public void test(String s){ ????????long begin = System.currentTimeMillis(); ????????for(int i=0;i<ttime;i++){ ????????????s += "add"; ????????} ????????long over = System.currentTimeMillis(); ????????System.out.println("?操作?"+s.getClass().getName()+"?類型使用的時間為:?" ????????????+ (over - begin) + "?毫秒?" );??????? ????} ????public void test(StringBuffer s){ ????????long begin = System.currentTimeMillis(); ????????for(int i=0;i<ttime;i++){ ????????????s.append("add"); ????????} ????????long over = System.currentTimeMillis(); ????????System.out.println("?操作?"+s.getClass().getName()+"?類型使用的時間為:?" ????????????+ (over - begin) + "?毫秒?" );??????? ????} ????public void test(StringBuilder s){ ????????long begin = System.currentTimeMillis(); ????????for(int i=0;i<ttime;i++){ ????????????s.append("add"); ????????} ????????long over = System.currentTimeMillis(); ????????System.out.println("?操作?"+s.getClass().getName()+"?類型使用的時間為:?" ????????????+ (over - begin) + "?毫秒?" );??????? ????} ????//?對?String?直接進行字符串拼接的測試 ????public void test2(){ ????????String s2 = "abadf"; ????????long begin = System.currentTimeMillis(); ????????for(int i=0;i<ttime;i++){ ????????????String s = s2 + s2 + s2 ; ????????} ????????long over = System.currentTimeMillis(); ????????System.out.println("?操作字符串對象引用相加類型使用的時間為:?" ????????????+ (over - begin) + "?毫秒?" );??????? ????} ????public void test3(){ ????????long begin = System.currentTimeMillis(); ????????for(int i=0;i<ttime;i++){ ????????????String s = "abadf" + "abadf" + "abadf" ; ????????} ????????long over = System.currentTimeMillis(); ????????System.out.println("?操作字符串相加使用的時間為:?" ????????????+ (over - begin) + "?毫秒?" );??????? ????} ??? ????public static void main(String[] args){ ????String s1 ="abc"; ????StringBuffer sb1 = new StringBuffer("abc"); ????StringBuilder sb2 = new StringBuilder("abc"); ????testssb t = new testssb(); ????t.test(s1); ????t.test(sb1); ????t.test(sb2); ????t.test2(); ????t.test3(); ????} } |
以上代碼在?NetBeans 5.0 IDE/JDK1.6?上編譯通過
循環次數?ttime?為?10000?次的測試結果如下:
| 操作?java.lang.String?類型使用的時間為:?4392?毫秒 操作?java.lang.StringBuffer?類型使用的時間為:?0?毫秒 操作?java.lang.StringBuilder?類型使用的時間為:?0?毫秒 操作字符串對象引用相加類型使用的時間為:?15?毫秒 操作字符串相加使用的時間為:?0?毫秒 |
好像還看不出?StringBuffer?和?StringBuilder?的區別,把?ttime?加到?30000?次看看:
| 操作?java.lang.String?類型使用的時間為:?53444?毫秒 操作?java.lang.StringBuffer?類型使用的時間為:?15?毫秒 操作?java.lang.StringBuilder?類型使用的時間為:?15?毫秒 操作字符串對象引用相加類型使用的時間為:?31?毫秒 操作字符串相加使用的時間為:?0?毫秒 |
StringBuffer?和?StringBuilder?的性能上還是沒有太大的差異,再加大到?100000?看看,這里就不加入對?String?類型的測試了,因為對?String?類型這么大數據量的測試會很慢滴……
| 操作?java.lang.StringBuffer?類型使用的時間為:?31?毫秒 操作?java.lang.StringBuilder?類型使用的時間為:?16?毫秒 |
能看出差別了,但其中有多次的測試結果居然是?StringBuffer?比?StringBuilder?快,再加大一些到?1000000?看看(應該不會當機吧?):
| 操作?java.lang.StringBuffer?類型使用的時間為:?265?毫秒 操作?java.lang.StringBuilder?類型使用的時間為:?219?毫秒 |
有些少區別了,而且結果很穩定,再大點看看,?ttime = 5000000?:
······?Exception in thread "main" java.lang.OutOfMemoryError: Java heap space?······
呵呵,算了,不去測試了,基本來說都是在性能上都是?StringBuilder > StringBuffer > String?的了。
轉載于:https://www.cnblogs.com/nanguabing/archive/2012/09/20/2694592.html
總結
以上是生活随笔為你收集整理的String , StringBuffer 和 StringBuilder 区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lnmp平台搭建
- 下一篇: Android网络编程