首頁  >  文章  >  Java  >  Java StringBuilder和StringBuffer源碼分析

Java StringBuilder和StringBuffer源碼分析

高洛峰
高洛峰原創
2017-01-22 11:28:401169瀏覽

StringBuilder與StringBuffer是兩個常用的操作字串的類別。大家都知道,StringBuilder是線程不安全的,而StringBuffer是線程安全的。前者是JDK1.5加入的,後者在JDK1.0就有了。下面分析一下它們的內部實作。

一、繼承關係

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

可以看到,兩個類別的繼承關係是一模一樣的。 Serializable是可以序列化的標誌。 CharSequence介麵包含了charAt()、length() 、subSequence()、toString()這幾個方法,String類別也實作了這個介面。這裡的重點是抽象類別AbstractStringBuilder,這個類別封裝了StringBuilder和StringBuffer大部分運算的實作。

二、AbstractStringBuilder

1、變數及建構方法

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

AbstractStringBuilder內部用一個char[]陣列保存字串,可以在建構的時候指定初始容量方法。

2、擴容

public void ensureCapacity(int minimumCapacity) {
  if (minimumCapacity > 0)
    ensureCapacityInternal(minimumCapacity);
}
 private void ensureCapacityInternal(int minimumCapacity) {
  // overflow-conscious code
  if (minimumCapacity - value.length > 0)
    expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
  int newCapacity = value.length * 2 + 2;
  if (newCapacity - minimumCapacity < 0)
    newCapacity = minimumCapacity;
  if (newCapacity < 0) {
    if (minimumCapacity < 0) // overflow
      throw new OutOfMemoryError();
    newCapacity = Integer.MAX_VALUE;
  }
  value = Arrays.copyOf(value, newCapacity);
}

擴容的方法最終是由expandCapacity()實現的,在這個方法中首先把容量擴大為原來的容量加2,如果此時仍小於指定的容量,那麼就把新的容量設為minimumCapacity。然後判斷是否溢出,如果溢出了,把容量設為Integer.MAX_VALUE。最後把value值進行拷貝,這顯然是耗時操作。

3、append()方法

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;
  }

append()是最常用的方法,它有很多形式的重載。上面是其中一種,用於追加字串。如果str是null,則會呼叫appendNull()方法。這個方法其實是追加了'n'、'u'、'l'、'l'這幾個字元。如果不是null,則先擴容,然後呼叫String的getChars()方法將str追加到value末端。最後回傳物件本身,所以append()可以連續呼叫。

三、StringBuilder

AbstractStringBuilder已經實作了大部分需要的方法,StringBuilder和StringBuffer只需要呼叫即可。下面來看看StringBuilder的實作。

1、建構器

public StringBuilder() {
  super(16);
}
public StringBuilder(int capacity) {
  super(capacity);
}
public StringBuilder(String str) {
  super(str.length() + 16);
  append(str);
}
public StringBuilder(CharSequence seq) {
  this(seq.length() + 16);
  append(seq);
}

可以看出,StringBuilder預設的容量大小為16。當然也可以指定初始容量,或以一個已有的字元序列為StringBuilder物件賦初始值。

2、append()方法

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

append()的重載方法很多,這裡隨便列舉了兩個。顯然,這裡是直接呼叫的父類別AbstractStringBuilder中的方法。

3、toString()

public String toString() {
  // Create a copy, don&#39;t share the array
  return new String(value, 0, count);
}

toString()方法傳回了一個新的String對象,與原來的物件不共享記憶體。其實AbstractStringBuilder中的subString()方法也是如此。

四、SringBuffer

StiringBuffer跟StringBuilder類似,只不過為了實現同步,很多方法使用lSynchronized修飾,如下面的方法:

public synchronized int length() {
    return count;
}
public synchronized StringBuffer append(String str) {
  toStringCache = null;
  super.append(str);
  return this;
}
public synchronized void setLength(int newLength) {
  toStringCache = null;
  super.setLength(newLength);
}

  

另外,在上面的append()以及setLength()方法裡面還有個變數toStringCache。這個變數是用於最近一次toString()方法的緩存,任何時候只要StringBuffer被修改了這個變數會被賦值為null。 StringBuffer的toString如下:

public synchronized String toString() {
  if (toStringCache == null) {
    toStringCache = Arrays.copyOfRange(value, 0, count);
  }
  return new String(toStringCache, true);
}


在這個方法中,如果toStringCache為null則先快取。最後回傳的String物件有點不同,這個建構方法還有個參數true。找到String的原始碼看一下:

String(char[] value, boolean share) {
  // assert share : "unshared not supported";
  this.value = value;
}

原來這個建構方法建構出來的String物件並沒有實際複製字串,只是把value指向了建構參數,這是為了節省複製元素的時間。不過這個構造器是具有套件存取權限,一般情況下是不能呼叫的。

總結

StringBuilder和StringBuffer都是可變字串,前者執行緒不安全,後者執行緒安全。

StringBuilder和StringBuffer的大部分方法都呼叫父類別AbstractStringBuilder的實作。其擴容機制首先是將容量變成原來容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。

StringBuilder和StringBuffer的預設容量都是16,最好預先估計好字串的大小避免擴容帶來的時間消耗。

以上就是本文的全部內容,希望對大家學習Java中兩個常用的操作字串的類別StringBuilder和StringBuffer有所幫助。

更多Java StringBuilder和StringBuffer源碼分析相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn