Android(java):StringBuffer StringBulider區別

java數組複製 System.copyarray()方法

System.copyarray()方法可以用來複制數組,其格式是:

System.arraycopy(Object src, int src_position, Object dst, int dst_position, int length)

它將數組從src 複製到dst,複製的位置是src 的第src_position 個元素到dst 的第dst_position

位置,複製元素的個數爲length。

注意:該方法只複製元素。如果數組元素是引用型變量,則只複製引用,不復制對象

實體。

 
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)

String 類型和 StringBuffer 、StringBuilder 類型的主要性能區別其實在於 String 是不可變的對象,而後倆者都是可變的。

來看看 StringBuffer類源碼定義:

Java代碼 複製代碼收藏代碼
  1.   
  2. public finalclass StringBuffer 
  3.     extends AbstractStringBuilder 
  4.     implements java.io.Serializable, CharSequence 
  5.  
  6.     public StringBuffer() { 
  7.     super(16); 
  8.     } 
  9.  
  10.      public StringBuffer(int capacity) { 
  11.     super(capacity); 
  12.     } 
  1. <STRONG>   
  2. public final class StringBuffer  
  3.     extends AbstractStringBuilder  
  4.     implements java.io.Serializable, CharSequence  
  5. {  
  6.   
  7.     public StringBuffer() {  
  8.     super(16);  
  9.     }  
  10.   
  11.      public StringBuffer(int capacity) {  
  12.     super(capacity);  
  13.     }  
  14. </STRONG>  
 
public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    public StringBuffer() {
	super(16);
    }

     public StringBuffer(int capacity) {
	super(capacity);
    }


上例代碼我們發現 StringBuffer 繼承了 AbstractStringBuilder抽象類。包括構造方法的實現,都是父類提供的。

然後,我們打開 StringBuilder源碼定義:

Java代碼 複製代碼收藏代碼
  1. public finalclass StringBuilder 
  2.     extends AbstractStringBuilder 
  3.     implements java.io.Serializable, CharSequence 
  4.  
  5.     public StringBuilder() { 
  6.     super(16); 
  7.     } 
  8.  
  9.     public StringBuilder(int capacity) { 
  10.     super(capacity); 
  11.     } 
  1. <STRONG>public final class StringBuilder  
  2.     extends AbstractStringBuilder  
  3.     implements java.io.Serializable, CharSequence  
  4. {  
  5.   
  6.     public StringBuilder() {  
  7.     super(16);  
  8.     }  
  9.   
  10.     public StringBuilder(int capacity) {  
  11.     super(capacity);  
  12.     }  
  13. </STRONG>  
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    public StringBuilder() {
	super(16);
    }

    public StringBuilder(int capacity) {
	super(capacity);
    }

我們發現兩者都繼承了AbstractStringBuilder抽象類。且構造方法都調用父類實現。

我們接着看兩者append方法實現:

先看StringBuffer的:

Java代碼 複製代碼收藏代碼
  1.    
  2. public synchronized StringBuffer append(Object obj) { 
  3.        super.append(String.valueOf(obj)); 
  4.        return this
  5.    } 
  6.  
  7.    public synchronized StringBuffer append(String str) { 
  8.        super.append(str); 
  9.        return this
  10.    } 
  11.    //... 
  1. <STRONG>     
  2.  public synchronized StringBuffer append(Object obj) {  
  3.         super.append(String.valueOf(obj));  
  4.         return this;  
  5.     }  
  6.   
  7.     public synchronized StringBuffer append(String str) {  
  8.         super.append(str);  
  9.         return this;  
  10.     }  
  11.     //...   
  12. </STRONG>  
   
 public synchronized StringBuffer append(Object obj) {
        super.append(String.valueOf(obj));
        return this;
    }

    public synchronized StringBuffer append(String str) {
        super.append(str);
        return this;
    }
    //...


再看StringBuilder的:
Java代碼 複製代碼收藏代碼
  1. public StringBuilder append(Object obj) { 
  2.     return append(String.valueOf(obj)); 
  3.  
  4. public StringBuilder append(String str) { 
  5.     super.append(str); 
  6.     return this
  7. //... 
  1. <STRONG>      
  2.     public StringBuilder append(Object obj) {  
  3.         return append(String.valueOf(obj));  
  4.     }  
  5.   
  6.     public StringBuilder append(String str) {  
  7.         super.append(str);  
  8.         return this;  
  9.     }  
  10.     //...   
  11. </STRONG>  
    
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    //...


對比上面兩段源碼 我們發現 StirngBuffer 和StringBuilder的 append實現都是調用父類實現的。唯一不同的是 StringBuffer是線程安全的,方法中多了synchronized ,而StringBuilder 是非線程安全的。

我們看下父類AbstractStringBuilder 定義 及 append 實現:

Java代碼 複製代碼收藏代碼
  1. abstract class AbstractStringBuilderimplements Appendable, CharSequence { 
  2.     //底層與String類一樣都是 char類型數組。 
  3.     char value[]; 
  4.     //字符串長度 
  5.     int count; 
  6.  
  7.     AbstractStringBuilder() { 
  8.     } 
  9.  
  10.     AbstractStringBuilder(int capacity) { 
  11.         value = new char[capacity]; 
  12.     } 
  1. <STRONG>abstract class AbstractStringBuilder implements Appendable, CharSequence {  
  2.     //底層與String類一樣都是 char類型數組。   
  3.     char value[];  
  4.     //字符串長度   
  5.     int count;  
  6.   
  7.     AbstractStringBuilder() {  
  8.     }  
  9.   
  10.     AbstractStringBuilder(int capacity) {  
  11.         value = new char[capacity];  
  12.     }  
  13. </STRONG>  
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //底層與String類一樣都是 char類型數組。
    char value[];
    //字符串長度
    int count;

    AbstractStringBuilder() {
    }

    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }


Java代碼 複製代碼收藏代碼
  1. public AbstractStringBuilder append(Object obj) { 
  2.     return append(String.valueOf(obj)); 
  3.  
  4. public AbstractStringBuilder append(String str) { 
  5.     //對於str==null的 
  6.     if (str == null) str ="null"
  7.     int len = str.length(); 
  8.     if (len == 0)return this
  9.     //新的字符串長度 
  10.     int newCount = count + len; 
  11.     if (newCount > value.length) 
  12.          //當新的字符串長度比原先數組長度大時,需要對char 數組擴容。 
  13.            expandCapacity(newCount); 
  14.     //將新添的數據追加到char類型數組中。 
  15.      str.getChars(0, len, value, count); 
  16.     count = newCount; 
  17.     return this
  18.  
  19. //數組擴容  
  20. void expandCapacity(int minimumCapacity) { 
  21.     //先擴容成 (原先的長度+1)*2 
  22.     int newCapacity = (value.length +1) * 2
  23.     //判斷newCapacity值是否滿足要求 
  24.      //如果新的長度還是不夠,則直接取值 minimumCapacity  
  25.     if (newCapacity < 0) { 
  26.        newCapacity = Integer.MAX_VALUE; 
  27.     } else if (minimumCapacity > newCapacity) { 
  28.        newCapacity = minimumCapacity; 
  29.     }    
  30.     char newValue[] = new char[newCapacity]; 
  31.     //將原先的數據拷貝到新的char 數組中。 
  32.      System.arraycopy(value, 0, newValue,0, count); 
  33.     value = newValue; 
  34.  
  35. public void getChars(int srcBegin,int srcEnd, char dst[],int dstBegin) { 
  36.     if (srcBegin < 0) { 
  37.         throw new StringIndexOutOfBoundsException(srcBegin); 
  38.     } 
  39.     if (srcEnd > count) { 
  40.         throw new StringIndexOutOfBoundsException(srcEnd); 
  41.     } 
  42.     if (srcBegin > srcEnd) { 
  43.         throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); 
  44.     } 
  45.     System.arraycopy(value, offset + srcBegin, dst, dstBegin, 
  46.          srcEnd - srcBegin); 

StringBuffer與StringBuilder是java.lang包下被大家熟知的兩個類。其異同爲:一、長度都是可擴充的;二、StringBuffer是線程安全的,StringBuilder是線程不安全的。那麼他們的長度是如何實現動態擴充以及StringBuffer的線程安全是如何實現的呢?通過“深度”閱讀它們的源代碼,最終弄明白其中的緣由。

正文

首先上一張StringBuffer和StringBuilder類結構圖:


抽象類AbstractStringBuilder(也是核心實現類)實現了Appendable和CharSequence兩個接口;StringBuffer與StringBuilder統統繼承自AbstractStringBuilder,並且實現了java.io.Serializable和CharSequence接口。

下面簡單描述下這幾個接口所起到的作用(引用自中文api)。

  • Appendable:能夠被添加 char 序列和值的對象。如果某個類的實例打算接收java.util.Formatter 的格式化輸出,那麼該類必須實現 Appendable 接口
。要添加的字符應該是有效的 Unicode 字符,正如 Unicode Character Representation 中描述的那樣。注意,增補字符可能由多個 16 位char 值組成
  • CharSequence:CharSequence 是 char 值的一個可讀序列。此接口對許多不同種類的 char 序列提供統一的只讀訪問。char 值表示 Basic Multilingual Plane (BMP) 或代理項中的一個字符。有關詳細信息,請參閱Unicode 字符表示形式。此接口不修改equalshashCode 方法的常規協定。因此,通常未定義比較實現 CharSequence 的兩個對象的結果。每個對象都可以通過一個不同的類實現,而且不能保證每個類能夠測試其實例與其他類的實例的相等性。因此,使用任意 CharSequence 實例作爲集合中的元素或映射中的鍵是不合適的。
  • Serializable:類通過實現 java.io.Serializable 接口以啓用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用於標識可序列化的語義。
  • AbstractStringBuilde
r這個抽象類提供了StringBuffer和StringBuilder絕大部分的實現。在AbstractStringBuilder的描述中說:如果去掉線程安全,那麼StringBuffer和StringBuilder是完全一致的。從實現的角度來說,StringBuffer所有方法(構造方法除外,因爲沒有必要)簽名中都使用synchronized限定,也就是所有的方法都是同步的。

eg.StringBuffer中replace()方法

1 public synchronized StringBuffer replace(intstart, int end, String str) {
2 super.replace(start, end, str);
3 return this;
4 }

StringBuilder中replace():

1 public StringBuilder replace(intstart, int end, String str) {
2 super.replace(start, end, str);
3 return this;
4 }

區別僅僅在方法簽名上是否有synchronized。

另外需要稍稍注意的問題是:StringBuffer同步只同步目標,比如:sb.append("i am not synchronized"),sb是同步的,而其中的參數未必是同步的。

而它們兩個可擴展長度則是通過ensureCapacity(int minimumCapacity)來驗證當前長度是否小於參數minimumCapacity,如果成立則進行分配空間。分配新空間的步長爲(當前長度+1)的兩倍。

實現如下:

01 public void ensureCapacity(intminimumCapacity) {
02 if (minimumCapacity > value.length) {
03 expandCapacity(minimumCapacity);
04 }
05 }
06 void expandCapacity(int minimumCapacity) {
07 int newCapacity = (value.length + 1) *2;
08 if (newCapacity < 0) {
09 newCapacity = Integer.MAX_VALUE;
10 } else if (minimumCapacity > newCapacity) {
11 newCapacity = minimumCapacity;
12 }
13 value = Arrays.copyOf(value, newCapacity);
14 }

如果新的長度小於0(溢出了),則使用Integer的最大值作爲長度。

另外,在閱讀源碼的過程中,發現兩個有趣的問題,下面一一道來。

第一個,就是reverse的實現。其實我是第一次看StringBuilder和StringBuffer的源碼,這裏面的reverse的實現是我所知道的java中的最高效的實現,沒有之一。

上源碼,再做解釋:

01 public AbstractStringBuilder reverse() {
02 boolean hasSurrogate = false;
03 int n = count - 1;
04 for (int j = (n-1) >>1; j >= 0; --j) {
05 char temp = value[j];
06 char temp2 = value[n - j];
07 if (!hasSurrogate) {
08 hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
09 || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
10 }
11 value[j] = temp2;
12 value[n - j] = temp;
13 }
14 if (hasSurrogate) {
15 // Reverse back all valid surrogate pairs
16 for (int i = 0; i < count -1; i++) {
17 char c2 = value[i];
18 if (Character.isLowSurrogate(c2)) {
19 char c1 = value[i + 1];
20 if (Character.isHighSurrogate(c1)) {
21 value[i++] = c1;
22 value[i] = c2;
23 }
24 }
25 }
26 }
27 return this;
28 }

reverse分成兩個部分:前面一個循環與後面的判斷。

首先地一個循環很高效,循環次數爲長度(count)的一半,而且使用>>位移運算,交換數組value[j]與value[n-j]的值。這裏一是循環次數少,而是使用最高效的位移運算所以說這個reverse很高效。在反轉過程中還完成了一件事:就是爲hasSurrogate賦值。賦值的依據就是value[j]與value[n-j]兩個字符時候有一個在\uD800和\uDFFF之間,如果有則賦值爲true。

 

  1. <STRONG>      
  2.     public AbstractStringBuilder append(Object obj) {  
  3.         return append(String.valueOf(obj));  
  4.     }  
  5.       
  6.     public AbstractStringBuilder append(String str) {  
  7.         //對於str==null的   
  8.         if (str == null) str = "null";  
  9.         int len = str.length();  
  10.         if (len == 0return this;  
  11.         //新的字符串長度   
  12.         int newCount = count + len;  
  13.         if (newCount > value.length)  
  14.              //當新的字符串長度比原先數組長度大時,需要對char 數組擴容。  
  15.                expandCapacity(newCount);  
  16.         //將新添的數據追加到char類型數組中。   
  17.          str.getChars(0, len, value, count);  
  18.         count = newCount;  
  19.         return this;  
  20.     }  
  21.       
  22.     //數組擴容    
  23.     void expandCapacity(int minimumCapacity) {  
  24.         //先擴容成 (原先的長度+1)*2   
  25.         int newCapacity = (value.length + 1) * 2;  
  26.         //判斷newCapacity值是否滿足要求   
  27.          //如果新的長度還是不夠,則直接取值 minimumCapacity   
  28.         if (newCapacity < 0) {  
  29.            newCapacity = Integer.MAX_VALUE;  
  30.         } else if (minimumCapacity > newCapacity) {  
  31.            newCapacity = minimumCapacity;  
  32.         }     
  33.         char newValue[] = new char[newCapacity];  
  34.         //將原先的數據拷貝到新的char 數組中。   
  35.          System.arraycopy(value, 0, newValue, 0, count);  
  36.         value = newValue;  
  37.     }  
  38.   
  39.      public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {  
  40.         if (srcBegin < 0) {  
  41.             throw new StringIndexOutOfBoundsException(srcBegin);  
  42.         }  
  43.         if (srcEnd > count) {  
  44.             throw new StringIndexOutOfBoundsException(srcEnd);  
  45.         }  
  46.         if (srcBegin > srcEnd) {  
  47.             throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);  
  48.         }  
  49.         System.arraycopy(value, offset + srcBegin, dst, dstBegin,  
  50.              srcEnd - srcBegin);  
  51.     }  
  52. </STRONG>  
    
    public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    
    public AbstractStringBuilder append(String str) {
        //對於str==null的
        if (str == null) str = "null";
        int len = str.length();
        if (len == 0) return this;
        //新的字符串長度
        int newCount = count + len;
        if (newCount > value.length)
             //當新的字符串長度比原先數組長度大時,需要對char 數組擴容。
               expandCapacity(newCount);
        //將新添的數據追加到char類型數組中。
         str.getChars(0, len, value, count);
        count = newCount;
        return this;
    }
    
    //數組擴容 
    void expandCapacity(int minimumCapacity) {
        //先擴容成 (原先的長度+1)*2
        int newCapacity = (value.length + 1) * 2;
        //判斷newCapacity值是否滿足要求
         //如果新的長度還是不夠,則直接取值 minimumCapacity 
        if (newCapacity < 0) {
           newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
           newCapacity = minimumCapacity;
        }	
        char newValue[] = new char[newCapacity];
        //將原先的數據拷貝到新的char 數組中。
         System.arraycopy(value, 0, newValue, 0, count);
        value = newValue;
    }

     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > count) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, offset + srcBegin, dst, dstBegin,
             srcEnd - srcBegin);
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章