1. 程式人生 > 實用技巧 >Java基礎07 String、StringBuilder、StringBuffer的區別

Java基礎07 String、StringBuilder、StringBuffer的區別

String 類

  在Java的程式設計中,字串是運用的比較多的型別,字串是由Java的String類來建立的,需要注意的是String類被 final 修飾的類,這意味著該類不能繼承,該類的物件值是不可變的。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

  但在平時使用的時候,我們經常這樣操作來改變String物件變數的值

String str = "hello";
str += "world"; 

  其實這樣的操作很消耗記憶體,浪費儲存空間,我們來看下上面的語句塊會產生哪些操作。

  1. 在堆上開闢一個空間用於儲存 hello
  2. 在棧上分配一個空間用於儲存str,儲存的值是堆記憶體的 hello 地址
  3. 在堆上開闢一個空間用於儲存 world.
  4. 拼接 hello 與 world.兩個字串,放入堆另外開闢的一個記憶體空間
  5. 棧上儲存str的值變為 helloworld. 的堆記憶體地址

  經過上面的步驟分析,我們可以知道,String 型別的字串在進行拼接的時候,在堆記憶體上開闢了三次空間,而且只使用其中一個記憶體空間,這無疑是對堆記憶體空間的極大的浪費。

  為了能解決這個問題,也就引入了 StringBuild 和 StringBuffer。

StringBuffer與StringBuilder

  StringBuilder 與 StringBuffer 兩個類主要用於對字串頻繁修改的場景,它們是對 String 的優化,在追加字串的時候不會去堆上開闢新的空間,會直接在已有的堆空間追加。

  上圖是String、StringBuffer、StringBuilder的層級關係圖,我們可以看出StringBuilder與StringBuffer繼承了AbstractStringBuilder抽象類,檢視原始碼可知,StringBuilder與StringBuffer最終使用的方法還是它們的父類AbstractStringBuilder中的方法,唯一不同的是StringBuffer比StringBuilder多做了一個加鎖的操作,這也就導致StringBuffer是執行緒安全的,但執行效率比較低,而StringBuilder不是執行緒安全的,但執行效率較高。

StringBuilder

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);	// 呼叫本類的
}

@Override
public StringBuilder append(String str) {	// 沒有加鎖
    super.append(str);	// 直接呼叫父類的追加方法
    return this;
}

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

StringBuffer

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);	// 呼叫本類的
}

@Override
public synchronized StringBuffer append(String str) {	// 加鎖
    toStringCache = null;
    super.append(str);	// 呼叫父類的追加方法
    return this;
}

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

  可能有些疑問,為什麼String、StringBuilder、StringBuffer三個類都是被 final 修飾,但只有String的值是不可變的呢?
  其實很簡單,StringBuilder、StringBuffer確實是被 final 修飾的,而且他們本身也確實是不可變的,但我們需要注意的一點,他們追加的真正操作是在它們的父類中進行的,而它們的父類是沒有被 final 修飾,這也就間接的理解StringBuilder、StringBuffer是可變的字串,追加的時候不需要在堆記憶體開闢新的空間。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

總結:三者的區別

  1. 三者都是被 final 修飾的類,但String類是不可變的,而其它兩個可以間接理解為可變的。
  2. StringBuilder和String不是執行緒安全的,StringBuffer是執行緒安全的。
  3. 效率:StringBuilder > StringBuffer。
  4. 在字串變數的值不經常改變的情況下(甚至不變),可以使用String,也可以使用StringBuilder;在字串變數的值經常改變且不是多執行緒環境下,使用StringBuilder;在字串變數的值經常改變且在多執行緒環境下,使用StringBuffer.