【轉】Java:String、StringBuffer和StringBuilder的區別

1 String

String:字符串常量,字符串長度不可變。Java中String是immutable(不可變)的。html

String類的包含以下定義:java

 

[java]  view plaincopy
  1. /** The value is used for character storage. */  
  2. private final char value[];  
  3.   
  4. /** The offset is the first index of the storage that is used. */  
  5. private final int offset;  
  6.   
  7. /** The count is the number of characters in the String. */  
  8. private final int count;  

用於存放字符的數組被聲明爲final的,所以只能賦值一次,不可再更改。程序員

 

2 StringBuffer(JDK1.0)

StringBuffer:字符串變量(Synchronized,即線程安全)。若是要頻繁對字符串內容進行修改,出於效率考慮最好使用StringBuffer,若是想轉成String類型,能夠調用StringBuffer的toString()方法。web

Java.lang.StringBuffer線程安全的可變字符序列。在任意時間點上它都包含某種特定的字符序列,但經過某些方法調用能夠改變該序列的長度和內容。可將字符串緩衝區安全地用於多個線程。編程

StringBuffer 上的主要操做是 append 和 insert 方法,可重載這些方法,以接受任意類型的數據。每一個方法都能有效地將給定的數據轉換成字符串,而後將該字符串的字符追加或插入到字符串緩衝區中。append 方法始終將這些字符添加到緩衝區的末端;而 insert 方法則在指定的點添加字符。例如,若是 z 引用一個當前內容是「start」的字符串緩衝區對象,則此方法調用 z.append("le") 會使字符串緩衝區包含「startle」,而 z.insert(4, "le") 將更改字符串緩衝區,使之包含「starlet」。數組

3 StringBuilder(JDK5.0)

StringBuilder:字符串變量(非線程安全)。在內部,StringBuilder對象被看成是一個包含字符序列的變長數組。安全

java.lang.StringBuilder是一個可變的字符序列,是JDK5.0新增的。此類提供一個與 StringBuffer 兼容的 API,但不保證同步。該類被設計用做 StringBuffer 的一個簡易替換,用在字符串緩衝區被單個線程使用的時候(這種狀況很廣泛)。多線程

其構造方法以下:oracle

 

構造方法 描述
StringBuilder() 建立一個容量爲16的StringBuilder對象(16個空元素)
StringBuilder(CharSequence cs) 建立一個包含cs的StringBuilder對象,末尾附加16個空元素
StringBuilder(int initCapacity) 建立一個容量爲initCapacity的StringBuilder對象
StringBuilder(String s) 建立一個包含s的StringBuilder對象,末尾附加16個空元素

 

在大部分狀況下,StringBuilder > StringBuffer。這主要是因爲前者不須要考慮線程安全。app

4 三者區別

String 類型和StringBuffer的主要性能區別:String是不可變的對象, 所以在每次對String 類型進行改變的時候,都會生成一個新的 String 對象,而後將指針指向新的 String 對象,因此常常改變內容的字符串最好不要用 String ,由於每次生成對象都會對系統性能產生影響,特別當內存中無引用對象多了之後, JVM 的 GC 就會開始工做,性能就會下降。

使用 StringBuffer 類時,每次都會對 StringBuffer 對象自己進行操做,而不是生成新的對象並改變對象引用。因此多數狀況下推薦使用 StringBuffer ,特別是字符串對象常常改變的狀況下。

在某些特別狀況下, String 對象的字符串拼接實際上是被 Java Compiler 編譯成了 StringBuffer 對象的拼接,因此這些時候 String 對象的速度並不會比 StringBuffer 對象慢,例如:

 

[java]  view plaincopy
  1. String s1 = 「This is only a」 + 「 simple」 + 「 test」;  
  2. StringBuffer Sb = new StringBuilder(「This is only a」).append(「 simple」).append(「 test」);  

 

生成 String s1對象的速度並不比 StringBuffer慢。其實在Java Compiler裏,自動作了以下轉換:

 

Java Compiler直接把上述第一條語句編譯爲:

 

[java]  view plaincopy
  1. String s1 = 「This is only a simple test」;  

 

因此速度很快。但要注意的是,若是拼接的字符串來自另外的String對象的話,Java Compiler就不會自動轉換了,速度也就沒那麼快了,例如:

[java]  view plaincopy
  1. String s2 = 「This is only a」;  
  2. String s3 = 「 simple」;  
  3. String s4 = 「 test」;  
  4. String s1 = s2 + s3 + s4;  

這時候,Java Compiler會規規矩矩的按照原來的方式去作,String的concatenation(即+)操做利用了StringBuilder(或StringBuffer)的append方法實現,此時,對於上述狀況,若s2,s3,s4採用String定義,拼接時須要額外建立一個StringBuffer(或StringBuilder),以後將StringBuffer轉換爲String;若採用StringBuffer(或StringBuilder),則不需額外建立StringBuffer。

5 使用策略

(1)基本原則:若是要操做少許的數據,用String ;單線程操做大量數據,用StringBuilder ;多線程操做大量數據,用StringBuffer。

(2)不要使用String類的"+"來進行頻繁的拼接,由於那樣的性能極差的,應該使用StringBuffer或StringBuilder類,這在Java的優化上是一條比較重要的原則。例如:

 

[java]  view plaincopy
  1. String result = "";  
  2. for (String s : hugeArray) {  
  3.     result = result + s;  
  4. }  
  5.   
  6. // 使用StringBuilder  
  7. StringBuilder sb = new StringBuilder();  
  8. for (String s : hugeArray) {  
  9.     sb.append(s);  
  10. }  
  11. String result = sb.toString();  

當出現上面的狀況時,顯然咱們要採用第二種方法,由於第一種方法,每次循環都會建立一個String result用於保存結果,除此以外兩者基本相同(對於jdk1.5及以後版本)

 

(3)爲了得到更好的性能,在構造 StirngBuffer 或 StirngBuilder 時應儘量指定它們的容量。固然,若是你操做的字符串長度(length)不超過 16 個字符就不用了,當不指定容量(capacity)時默認構造一個容量爲16的對象。不指定容量會顯著下降性能。

(4)StringBuilder通常使用在方法內部來完成相似"+"功能,由於是線程不安全的,因此用完之後能夠丟棄。StringBuffer主要用在全局變量中。

(5)相同狀況下使用 StirngBuilder 相比使用 StringBuffer 僅能得到 10%~15% 左右的性能提高,但卻要冒多線程不安全的風險。而在現實的模塊化編程中,負責某一模塊的程序員不必定能清晰地判斷該模塊是否會放入多線程的環境中運行,所以:除非肯定系統的瓶頸是在 StringBuffer 上,而且肯定你的模塊不會運行在多線程模式下,才能夠採用StringBuilder;不然仍是用StringBuffer。

參考資料:

http://docs.oracle.com/javase/tutorial/java/data/buffers.html

http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4

Java API

相關文章
相關標籤/搜索