一.为什么要用StringBuilder?
在java中由于字符串的不可变性,即一旦创建就不能修改其内容,每次使用String类进行字符串拼接时,都会创建一个新的String对象,原有的String对象会被丢弃,为了解决这一问题,我们引入了StringBuilder 类,StringBuilder 是一个可变的字符序列,允许在原对象上进行修改,避免了创建大量的中间对象。
二.StringBuilder的扩容原理分析
1.创建StringBuilder 对象:
StringBuilder sb=new StringBuilder();
2.调用 StringBuilder 的构造方法
public StringBuilder() {
super(16);
}
3.调用父类 AbstractStringBuilder 的构造方法,创建一个初始容量为16的char[] value数组
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
4.调用append方法获取追加字符串长度
检查要追加的字符串,如果不为空,计算要追加的字符串长度,确保当前的 StringBuilder 有足够的容量存储追加的字符串。"你好呀"长度为3,ensureCapacityInternal(count + len),这里传入的值为3
for(int i=0;i<10;i++){
sb.append("你好呀");
}
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;
}
5.调用容量确认方法ensureCapacityInternal确认是否需要扩容
此时3-16<0,不需要扩容,所以执行下一句代码str.getChars(0, len, value, count);
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
调用str.getChars(0, len, value, count)给arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin)传值,此时value=3,srcBegin=0,srcEnd=追加的字符串长度=3dst是初始容量为16的char[] value数组,dstBegin=count=0
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
进行第六次循环时,count = 15,len = 3,minimumCapacity = 18,此时执行ensureCapacityInternal方法需要扩容,新的容量newCapacity=16*2+2=34
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
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;
}
三.总结
创建 StringBuilder 时,初始容量为 16。
在 for 循环中,每次调用 append 方法时,计算 minimumCapacity。
前五次循环时,minimumCapacity 未超过初始容量 16,因此不需要扩容。
第六次循环时,minimumCapacity 超过了初始容量,触发扩容,新容量为 34 (16 * 2 + 2)。