本文用于分析当创建StringBuffer对象后,调用append方法时,StringBuffer内部是如何扩容的
这是我们开发时经常做的
StringBuffer sb = new StringBuffer("abc");//原来数据的长度:3个字符
sb.append("defghijklmnopqrst");//新增加数据的长度:17个字符
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
上面的代码可以知道它调用的是父类AbstractStringBuilder的append方法,接着进入父类的append方法
//str-->"defghijklmnopqrst"
public AbstractStringBuilder append(String str) {
//新增加的数据为null则直接返回字符串"null"
if (str == null) str = "null";
int len = str.length();//新增加数据的长度为:17
ensureCapacityInternal(count + len);//扩容:count+len=3 + 17
str.getChars(0, len, value, count);//将原来的数据复制到扩容后的数组中
count += len;
return this;
}
从上面可以看出append方法调用了ensureCapacityInternal方法和str.getChars(0, len, value, count);,这里我们用3.1来分析前者(扩容操作),3.2来分析后者(将数据复制到扩容后的数组中)
===========================开始扩容=============================
//int minimumCapacity = 20
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code:判断是否需要扩容,也就是说原来的capacity是否足够大
if (minimumCapacity - value.length > 0) //20-19=1,1>0
expandCapacity(minimumCapacity);
}
上面的代码又调用了expandCapacity方法,我们用3.1下面的子标题来进行一步步分析
void expandCapacity(int minimumCapacity) { //int minimumCapacity=20
int newCapacity = value.length * 2 + 2; //新的容量capacity=原来的长度*2+2
//扩容后的容量-字符串实际长度<0(就是说如果扩容后还装不下),
//则使用字符串实际长度作为StringBuffer的capacity
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);
}
3.1.1.1 Arrays.copyOf(value, newCapacity)
//copyOf方法用于创建一个新数组,新数组的长度是扩容后的长度,并将原来的值复制到新的数组中
//这里需要注意,虽然数组是新的,但是StringBuffer还是原来的StringBuffer
//original:StringBuffer中原来的值,也就是'abc'
//newLength:新的长度,19*2+2=40
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
======================扩容结束======================
将字符从str字符串复制到目标数组value中,这里就是把str的所有值复制到value数组的最后面
//int srcBegin:字符串str中要复制的第一个字符的索引
//int srcEnd:字符串str中要复制的最后一个字符之后的索引
//char dst[]:目标数组
//int dstBegin:目标数组中的起始偏移量
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);