StringBuilder的容量capacity变化,是每次2倍增长吗?(jdk1.8)
测试代码 1
StringBuilder sb = new StringBuilder();
System.out.println(sb.capacity() + "----" + sb.length());
sb.append("0000_0000_0000_0");
System.out.println(sb.capacity() + "----" + sb.length());
sb.append("000");
System.out.println(sb.capacity() + "----" + sb.length());
sb.append("0000_0000_0000_0");
System.out.println(sb.capacity() + "----" + sb.length());
sb.append("0000_0000_0000_0");
System.out.println(sb.capacity() + "----" + sb.length());
运行结果 1
16----0
16----16
34----19
70----35
70----51
测试代码 2
StringBuilder sb = new StringBuilder();
sb.append("0000_0000_0000_0");
System.out.println(sb.capacity() + "----" + sb.length());
sb.append("0000_0000_0000_0000");
System.out.println(sb.capacity() + "----" + sb.length());
运行结果 2
16----16
35----35
问题
从运行结果1和运行结果2都能看出,StringBuilder的容量变化规律貌似不再是网上很多人所说的那样(容量默认为16,追加数据时,如果容量不够,则每次2倍整地扩容,直到容量不小于StringBuilder的长度值为止。)
那容量的变化规律到底是什么样的呢?接下来进入源码进行分析。
测试代码 1 的源码分析
public StringBuilder() {
super(16);
}
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* 该变量用于存储字符(可见StringBuilder底层用的是字符数组实现的)
* The value is used for character storage.
*/
char[] value;
/**
* 已使用的字符个数
* The count is the number of characters used.
*/
int count;
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
}
- 先进入StringBuilder的构造方法,其又调用了父类的构造,初始化容量capacity依然还是16。这就是为何运行结果1中第一组数据中容量capacity为16的原因。
sb.append("0000_0000_0000_0");
执行后因为长度还是16,没有超过当前容量(capacity = 16)的范围,所以运行结果还是不变。sb.append("000");
执行后,容量capacity突然变为34,竟然不是2*16=32,why?容量因为这句代码的执行发生了改变,那么容量的变化规则一定在append方法之中。进入append方法的源码发现:
ensureCapacityInternal(count + len);
这句代码就是重点,用于计算容量的大小的。
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;
}
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
其中minimumCapacity即为(count + len)的值,即 (已使用的字符个数 + 追加的新串的长度)的和(16 + 3 = 19),暂且叫最小容量值。
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0)
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
起初value.length为容量的默认值16,因newCapacity = value.length * 2 + 2;
所以有newCapacity = 34
即追加后的新容量为34。
容量的变化规律是2倍+2?
从测试代码1看起来下面的测试代码也能证明貌似是这样的,但是测试代码2的运行结果如何解释呢?,看源码,下面还有一句:
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
这句代码的意思是,如果原容量的2倍再加2的结果还小于最小容量值minimumCapacity的话,新的容量将按照最小容量值minimumCapacity来计算。此刻一切都明白了。
总结
StringBuilder的容量Capacity变化规则为:
- 初始值为16;
- 如果minimumCapacity(新添加的数据长度和已有数据长度的和)小于当前容量Capacity,则添加数据后容量Capacity不变;
- 如果minimumCapacity(新添加的数据长度和已有数据长度的和)大于当前容量Capacity,但minimumCapacity**小于**当前容量Capacity的2倍加2,则添加数据后容量Capacity变为上次容量的2倍加2;
- 如果minimumCapacity(新添加的数据长度和已有数据长度的和)大于当前容量Capacity的2倍加2,则添加数据后容量Capacity即为minimumCapacity(新添加的数据长度和已有数据长度的和)。
初始值 | 原容量 < 总内容 <= 2 * 原容量 + 2 | 总内容 > 2 * 原容量 + 2 |
---|
16 | 2 * 原容量 + 2 | 内容总长度 |
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)