JDK原始碼閱讀03---------AbstractStringBuilder、StringBuffer、StringBuilder
1.AbstractStringBuilder、StringBuffer、StringBuilder類簡介
字串廣泛應用 在Java 程式設計中,在 Java 中字串屬於物件,Java 提供了 String 類來建立和操作字串。
需要注意的是,String的值是不可變的,這就導致每次對String的操作都會生成新的String物件,這樣不僅效率低下,而且大量浪費有限的記憶體空間。
String是Java語言非常基礎和重要的類,提供了構造和管理字串的各種基本邏輯。它是典型的Immutable類,被宣告成為final class,所有屬性也都是final 的。也由於它的不可變性,類似拼接、裁剪字串等動作,都會產生新的String物件。由於字串操作的普遍性,所以相關操作的效率往往對應用效能有明顯影響
StringBuffer
是為解決上面提到拼接產生太多中間物件的問題而提供的一個類,我們可以用append
或者add
方法,把字串新增到已有序列的末尾或者指定位置。StringBuffer
本質是一個執行緒安全的可修改字元序列,它保證了執行緒安全,也隨之帶來了額外的效能開銷,所以除非有執行緒安全的需要,不然還是推薦使用它的後繼者,也就是StringBuilder.
StringBuilder
是Java 1.5中新增的,在能力上和StringBuffer
沒有本質區別,但是它去掉了執行緒安全的部分,有效減小了開銷,是絕大部分情況下進行字串拼接的首選。
StringBuffer
和 StringBuilder
char
,JDK 9
以後是 byte
)陣列,二者都繼承了AbstractStringBuilder
,裡面包含了基本操作,區別僅在於最終的方法是否加了 synchronized
。
2.原始碼閱讀
StringBuffer
與StringBuilder
都是繼承的AbstractStringBuilder
,二者中的主要方法與變數與AbstractStringBuilder
都類似,StringBuffer
和 StringBuilder
的區別主要在於最終的方法是否加了synchronized
關鍵字,這裡原始碼主要以AbstractStringBuilder
為主,有區別的地方再另行標註。
- 2.1 類定義
/**
*AbstractStringBuilder
*實現了兩個介面,其中CharSequence這個字元序列的介面已經很熟悉了:
該介面規定了需要實現該字元序列的長度:length();
可以取得下標為index的的字元:charAt(int index);
可以得到該字元序列的一個子字元序列: subSequence(int start, int end);
規定了該字元序列的String版本(重寫了父類Object的toString()):toString();
Appendable介面顧名思義,定義新增的’規則’:
append(CharSequence csq) throws IOException:如何新增一個字元序列
append(CharSequence csq, int start, int end) throws IOException:如何新增一個字元序列的一部分
append(char c) throws IOException:如何新增一個字元
*
*/
abstract class AbstractStringBuilder implements Appendable, CharSequence {}
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence{}
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{}
- 2.2變數
AbstractStringBuilder
/**
* 用於儲存字元序列的緩衝陣列
*/
char[] value;
/**
* 用於儲存實際儲存的字元數量
*/
int count;
/**
* 緩衝陣列最大長度(2^31-1)-8 約為21億
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
StringBuffer中特有的toStringCache
,用來快取StringBuffer最近一次toString的值,當StringBuffer出現任何其他操作或修改後,清空快取值。
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
- 2.3構造方法
AbstractStringBuilder
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
StringBuilder與StringBuffer的構造器基本相同,預設初始化陣列長度為,構建時初始字串長度加 16。
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
- 2.4常用方法
/**
* 獲取字串長度
*/
@Override
public int length() {
return count;
}
/**
* 獲取緩衝區的容量
*/
public int capacity() {
return value.length;
}
擴容相關實現:
擴容時,當現有容量值*2+2<所需最小容量
時,取所需最小容量
;
當現有容量值*2+2>=所需最小容量
時,取 現有容量*2+2
;
/**
* 緩衝陣列容量校驗
* 放入緩衝陣列所需要的的最小容量
*/
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
/**
* 當所需要的最小容量>當前陣列的容量時,取最小容量,建立新陣列,複製
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
/**
* 緩衝陣列最大長度(2^31-1)-8 約為21億
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 建立一個新容量的陣列:
* 當所需新容量>現有容量*2+2 時,取所需新容量大小
* 當新建新容量大小<0時,取最小容量
*
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
/**
* 當新建新容量>Integer.MAX_VALUE時,拋OutOfMemoryError();
* 當 MAX_ARRAY_SIZE<minCapacity <Integer.MAX_VALUE時,取minCapacity
*/
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
關於“空格”相關的方法:
/**
* 將快取陣列中的非空字元序列拷貝到新的陣列中
*/
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
/**
* 該函式沒有返回值。
若引數 newLength 大於或等於原長度,原來字串裡的字元位置不變,新多出來的位置 用 空字元(‘\0’)填充;
若引數 newLength 小於原長度,就相當於在原字串上擷取 newLength 長度的字串。
newLength >= 0
*/
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
if (count < newLength) {
Arrays.fill(value, count, newLength, '\0');
}
count = newLength;
}
AbstractStringBuilder
中的append()
方法,主要實現思路就是先確定容量,再通過getChars()
方法或者遍歷字元來將所需要的字串資訊追加至緩衝陣列中.
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
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;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
/**
* @since 1.8
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
return appendNull();
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
count += len;
return this;
}
....