science JDK1.0
在使用StringBuffer时一直没有留意capacity的扩增机制时怎样的,今天特意看下源码,了解一下。之前我看到一篇博文是说:旧的缓存空间*2+2进行扩容,他只是写了几行代码进行测试。我觉得比较好的是先看下源码再写个测试类,不要所以然。
我喜欢总结写在前面:StringBuffer的capacity扩增机制有三种,优先级依次是
1:原来的capacity*2+2
2:在第一中机制无法满足最小缓存要求的情况下将capacity设为当前存储字符串的大小
3:在第一和第二两个机制都无法满足的情况下,就要判断是否溢出了,并发出溢出报告,然后设置当前缓存空间为最大,但此时一定会发生数据截断。
下面是源码片段~
下面的代码是创建StringBuffer对象时的无参构造方式,可以看见它的 initial capacity 是16个字符,还有其它几种构造方式。
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
构造结束后我们调用append( )方法时,可以看见StringBuffer调用了它的父类AbstractStringBuilder 的append方法。
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
StringBuffer的父类AbstractStringBuilder 中的append方法,其中执行了ensureCapacityInternal()方法,来确保capacity足够大,能容下加入的字符。
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
ensureCapacityInternal()函数,传入的参数minimumCapacity是当前加入StringBuffer的字符串的长度。用minimumCapacity和value.length对比,(value.length是当前capacity的大小)如果minimumCapacity - value.length > 0,也就是如果要存入的字符串大于当前的缓存空间的话就执行expandCapacity()方法,将capacity进行扩容。
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
下面是个扩容的方法,传入的数值是当前要存入的字符串的长度(至于为什么命名为minimumCapacity是因为,你要存入的字符大小一定是StringBuffer的最小满足的缓存的大小)。很明显int newCapacity = value.length * 2 + 2;说明了如果缓存空间不够就增大为原来空间的两倍外加2。如果扩增后的缓存空间仍然不能满足最小空间要求就把要存入的字符串长度设为缓存空间的大小,然后判断是否溢出了,如果溢出,就把缓存空间设为最大(此时数据一定会发生截断)
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
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);
}