| String |
字串常量 |
- |
JDK1.0
|
| StringBuilder |
字串變數 |
線程不安全 |
JDK1.0
|
| StringBuffer |
字串變數 |
安全執行緒 |
JDK1.5
|
三者區別
String 類型和 StringBuffer 類型的主要效能區別其實在於 String 是不可變的對象, 因此在每次對 String 類型進行改變的時候其實都等同於產生了一個新的 String 對象,然後將指標指向新的 String 對象。如果經常改變字串內容,最好不要用 String ,因為每次產生對象都會對系統效能產生影響,而且當記憶體中無引用的對象多了以後, JVM 的 記憶體回收行程GC 就會開始工作,程式運行速度就會變慢。如果是定義一個StringBuffer 類型的對象,每次對字串內容進行操作都會對 StringBuffer對象本身進行操作,而不是產生新的對象。所以一般情況下推薦使用 StringBuffer ,特別是字串對象經常改變的情況下。StringBuffer中很多方法可以帶有synchronized關鍵字,所以可以保證線程是安全的,但StringBuilder的方法則沒有該關鍵字,所以不能保證安全執行緒。StringBuilder類提供一個與 StringBuffer 相容的 API,該類被設計用作 StringBuffer 的一個簡易替換,用在字串緩衝區被單個線程使用的時候。如果可能,建議優先採用該類,因為在大多數實現中,它比 StringBuffer 要快。兩者的方法基本相同。
在某些特殊的情況下,String的效率比StringBuffer要快,例如:
String s1 = "123" + "456" + "789";StringBuffer s2 = new StringBuffer("123").append("456").append("789");
第一行代碼在java虛擬機器看來其實就是:
String s1 = "123456789";
因為在編譯期就已經完成了。
關於字串==的問題
public static void main(String[] args) { String s1=new String("123"); String s2=new String("123"); System.out.println("s1==s2 :" + (s1==s2)); // false String s3="456"; String s4="456"; System.out.println("s3==s4 :" + (s3==s4)); // true }輸出:s1==s2 :falses3==s4 :true
s1和s2是java虛擬機器在堆記憶體new出來的兩個String對象的記憶體位址,雖然他們的值一樣,但是==比較的是地址,所以是false。而s3和s4是在常量池中儲存的,就是常量池中“456”指向的唯一的保留字元串對象的地址,所以是true。
public static void main(String[] args) { String s1 = "123"; String s2 = "456"; String s12 = s1 + s2; String s="123456"; System.out.println(s12==s); // false }
變數s1,s2儲存的是常量池中的地址。當執行s1+s2時,JVM首先會在堆中建立一個StringBuilder類,同時用s1指向的字串對象完成初始化,然後調用append方法完成對s2所指向的字串進行合併作業,接著調用StringBuilder的toString()方法在堆中建立一個String對象,最後將剛產生的String對象的堆地址存放在變數s12中。而變數s儲存的是常量池中"abcd"所對應的字串對象的地址。s12與s地址肯定不一樣。
總結
String:適用於少量的字串操作的情況
StringBuilder:適用於單線程下在字元緩衝區進行大量操作的情況
StringBuffer:適用多線程下在字元緩衝區進行大量操作的情況
在編譯期就能夠確定的字串常量,沒有必要建立String或StringBuffer對象。直接使用字串常量的"+"串連操作效率最高。