String和StringBuffer和StringBuilder的區別
String和StringBuffer和StringBuilder的區別
簡要的說, String 型別和 StringBuffer 型別的主要效能區別其實在於 String 是不可變的物件, 因此在每次對 String 型別進行改變的時候其實都等同於生成了一個新的 String 物件,然後將指標指向新的 String 物件,這樣不僅效率低下,而且大量浪費有限的記憶體空間,所以經常改變內容的字串最好不要用 String 。因為每次生成物件都會對系統性能產生影響,特別當記憶體中無引用物件多了以後, JVM 的 GC 就會開始工作,那速度是一定會相當慢的。
String | StringBuffer | StringBuilder |
---|---|---|
String的值是不可變的,這就導致每次對String的操作都會生成新的String物件,不僅效率低下,而且浪費大量優先的記憶體空間 | StringBuffer是可變類,和執行緒安全的字串操作類,任何對它指向的字串的操作都不會產生新的物件。每個StringBuffer物件都有一定的緩衝區容量,當字串大小沒有超過容量時,不會分配新的容量,當字串大小超過容量時,會自動增加容量 | 可變類,速度更快 |
不可變 | 可變 | 可變 |
執行緒安全 (所有公開方法都是 synchronized 修飾的) | 執行緒不安全(沒有 StringBuilder 修飾) | |
多執行緒操作字串 | 單執行緒操作字串 |
當對字串進行修改的時候,特別是字串物件經常改變的情況下,需要使用 StringBuffer 和 StringBuilder 類。
和 String 類不同的是,StringBuffer 和 StringBuilder 類的物件能夠被多次的修改,並且不產生新的未使用物件。
由於 StringBuilder 相較於 StringBuffer 有速度優勢,所以多數情況下建議使用 StringBuilder 類。然而在應用程式要求執行緒安全的情況下,則必須使用 StringBuffer 類。
三者的繼承關係
三者的區別
小結:(1)如果要操作少量的資料用 String;
(2)多執行緒操作字串緩衝區下操作大量資料 StringBuffer;
(3)單執行緒操作字串緩衝區下操作大量資料 StringBuilder
StringBuffer與String的可變性問題。
我們先看看這兩個類的部分原始碼:
Java程式碼
//String
public final class String
{
private final char value[];
public String(String original) {
// 把原字串original切分成字元陣列並賦給value[];
}
}
//StringBuffer
public final class StringBuffer extends AbstractStringBuilder
{
char value[]; //繼承了父類AbstractStringBuilder中的value[]
public StringBuffer(String str) {
super(str.length() + 16); //繼承父類的構造器,並建立一個大小為str.length()+16的value[]陣列
append(str); //將str切分成字元序列並加入到value[]中
}
}
很顯然,String和StringBuffer中的value[]都用於儲存字元序列。但是,
(1) String中的是常量(final)陣列,只能被賦值一次。
比如:new String("abc")使得value[]={'a','b','c'}(檢視jdk String 就是這麼實現的),之後這個String物件中的value[]再也不能改變了。這也正是大家常說的,String是不可變的原因 。
注意:這個對初學者來說有個誤區,有人說String str1=new String("abc"); str1=new String("cba");不是改變了字串str1嗎?那麼你有必要先搞懂物件引用和物件本身的區別。這裡我簡單的說明一下,物件本身指的是存放在堆空間中的該物件的例項資料(非靜態非常量欄位)。而物件引用指的是堆中物件本身所存放的地址,一般方法區和Java棧中儲存的都是物件引用,而非物件本身的資料。
(2) StringBuffer中的value[]就是一個很普通的陣列,而且可以通過append()方法將新字串加入value[]末尾。這樣也就改變了value[]的內容和大小了。