StringBuffer類的概念
線程安全的可變字符序列。一個類似於 String的字符串緩衝區,但不能修改。雖然在任意時間點上它都包含某種特定的字符序列,但通過某些方法調用可以改變該序列的長度和內容。
StringBuffer上的主要操作是 append 和 insert 方法,可重載這些方法,以接受任意類型的數據。每個方法都能有效地將給定的數據轉換成字符串,然後將該字符串的字符添加或插入到字符串緩衝區中。append 方法始終將這些字符添加到緩衝區的末端;而 insert 方法則在指定的點添加字符。
每個字符串緩衝區都有一定的容量。只要字符串緩衝區所包含的字符序列的長度沒有超出此容量,就無需分配新的內部緩衝區數組。如果內部緩衝區溢出,則此容量自動增大。
StringBuffer擴容的原理
源碼分析:
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
/**
* Constructs a string buffer with no characters in it and
* the specified initial capacity.
*
* @param capacity the initial capacity.
* @exception NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuffer(int capacity) {
super(capacity);
}
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by the same amount + 2 if
* that suffices.
* Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
* unless the given minimum capacity is greater than that.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero or
* greater than Integer.MAX_VALUE
*/
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;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
通過源碼分析得知,使用append()方法在字符串後面追加元素的時候,如果長度超過了該字符串存儲空間大小就需要進行擴容,需要構建新的存儲空間存儲更大的字符串,並將新生成的字符串複製過去;擴容的時候會調取一個newCapacity()方法對容量是否擴容進行判斷,所以每次擴容都會在原有容量上左移一位再加2(相當於乘以2+2)。
下面通過具體代碼來看下擴容過程:
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
sb.append(true);
sb.append('a');
sb.append("abc");
sb.append(20);
System.out.println("capacity==" + sb.capacity());
sb.append("helloworld");//開始第一次擴容
sb.append("helloworld");
System.out.println("capacity==" + sb.capacity());
sb.append("helloworld");//第二次擴容
//System.out.println(sb);
System.out.println("capacity==" + sb.capacity());
System.out.println(sb.length());
sb.insert(3, 123);
System.out.println(sb);
}
debug過程:
通過以上源碼分析和具體代碼的實現,只要掌握StringBuffer的擴容原理就很容易理解了。