String,StringBuilder,StringBuffer的區別

Null指標發表於2018-10-17

可變性

首先我們看下String的原始碼

  

/** The value is used for character storage. */
    private final char value[];
複製程式碼

由此可以看出,String類中使用final關鍵字字元陣列來儲存字串,所以是不可變的。

注:在Java中,final關鍵字可以用來修飾類、方法和變數(包括成員變數和區域性變數)

  1、當用final修飾一個類時,表明這個類不能被繼承。也就是說,如果一個類你永遠不會讓他被繼承,就可以用final進行修飾。

  2、final修飾的方法不能被重寫。

  3、當final修飾一個基本資料型別時,表示該基本資料型別的值一旦在初始化後便不能發生變化;如果final修飾一個引用型別時,則在對其初始化之後便不能再讓其指向其他物件了,但該引用所指向的物件的內容是可以發生變化的。

再來看下StringBuilder,StringBuffer的原始碼

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
...
}
public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
...
}
複製程式碼

由原始碼可以看出,StringBuilder、StringBuffer都繼承自AbstractStringBuilder類,我們接下來再看下AbstractStringBuilder類的原始碼

  

   /**
     * The value is used for character storage.
     */
    char[] value;
複製程式碼

由原始碼可以看出,StringBuilder、StringBuffer在AbstractStringBuilder中也是使用字元陣列儲存字串的,但是這兩種都是可變的。

執行緒安全性

String中的物件是不可變的,也可以理解為常量,執行緒安全的。

接下來我們繼續看下StringBuffer原始碼,我在這隨機擷取了原始碼中的一些方法

      /**
       * @throws StringIndexOutOfBoundsException {@inheritDoc}
       * @since      1.2
       */
      @Override
      public synchronized String substring(int start, int end) {
          return super.substring(start, end);
      }
  
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
     @Override
     public synchronized StringBuffer insert(int offset, Object obj) {
         toStringCache = null;
         super.insert(offset, String.valueOf(obj));
         return this;
     }
 
     /**
      * @since      1.4
      */
     @Override
     public int indexOf(String str) {
         // Note, synchronization achieved via invocations of other    
         StringBuffer methods
         return super.indexOf(str);
     }
複製程式碼

由原始碼可以看出StringBuffer對方法加了同步鎖或者對呼叫的方法加了同步鎖,所以是執行緒安全的。

再來看下StringBuilder原始碼中的一些方法

    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    
    /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
    @Override
    public StringBuilder insert(int index, char[] str, int offset,
                                 int len)
    {
        super.insert(index, str, offset, len);
        return this;
    }

    /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
    @Override
    public StringBuilder replace(int start, int end, String str) {
        super.replace(start, end, str);
        return this;
    }
複製程式碼

由原始碼可以看出,StringBuilder並沒有對方法進行加同步鎖,所以是非執行緒安全的。

效能

每次對 String 型別進行改變的時候,都會生成一個新的 String 物件,然後將指標指向新的 String 物件。

StringBuffer 每次都會對 StringBuffer 物件本身進行操作,而不是生成新的物件並改變物件引用。

相同情況下使用 StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的效能提升,但卻要冒多執行緒不安全的風險。

1、操作少量的資料 : String

2、單執行緒操作字串緩衝區下操作大量資料 : StringBuilder

3、多執行緒操作字串緩衝區下操作大量資料 : StringBuffer

相關文章