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的扩容原理就很容易理解了。