StringBuilder类的append()方法
- 进入主方法
public class Test {
public static void main (String[] args) {
StringBuilder sb = new StringBuilder("Romeo"); // 创建StringBuilder类对象sb
sb.append("Juliet"); // 调用append()方法对sb进行追加操作
System.out.println(sb); // 调用sb.toString()方法返回一个String类对象,调用该String对象的toString()方法,并打印该对象的内容
}
}
StringBuilder
类的两个重要属性
/**
* The value is used for character storage.
*/
char[] value; // value数组用于储存字符
/**
* The count is the number of characters used.
*/
int count; // count用于记录当前字符数组中的字符个数
- 进入
append()
方法
@Override
public StringBuilder append(String str) {
super.append(str); // 调用其父类AbstractStringBuilder的append()方法
return this; // 返回当前调用该方法的StringBuilder对象,相当于直接修改当前对象
}
- 进入其父类
AbstractStringBuilder
的append()
方法
public AbstractStringBuilder append(String str) {
if (str == null) // 传入的str没有任何指向
return appendNull();
int len = str.length(); // 获取当前传入的str的长度
ensureCapacityInternal(count + len); // 确保value数组可以装下count + len个字符,装不下则进入ensureCapacityInternal()方法对value数组进行扩容
str.getChars(0, len, value, count); // 将当前str字符串的字符依次拷贝到调用该append()方法的StringBuilder对象中的value数组中,StringBuilder对象中的value数组拷贝的起始下标为count
count += len; // 更新当前value数组中的字符个数
return this; // 返回当前调用该方法的对象
}
- 当传入的
str
没有任何指向时,进入appendNull()
方法
private AbstractStringBuilder appendNull() {
int c = count; // 定义临时变量c时刻指向value数组的末尾
ensureCapacityInternal(c + 4); // 确保value数组可以装下c + 4个字符
final char[] value = this.value; // 定义新的value数组指向属性value数组指向的空间(这里有疑惑,不清楚新定义一个final数组的意义,不清楚为什么不能在属性value数组上直接插入)
// 在新定义的value数组中插入null,属性value数组的内容也会发生变化
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c; // 更改当前value数组中的字符个数为c
return this; // 返回当前调用该方法的对象
}
- 当传入的
str
有具体指向时,进入ensureCapacityInternal()
方法
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) { // value数组当前的容量不足以存储minimumCapacity个字符
value = Arrays.copyOf(value,
newCapacity(minimumCapacity)); // 生成新数组,从value数组中下标为0的元素开始拷贝,拷贝长度为newCapacity个元素,如果原value数组中的元素个数小于newCapacity个,新数组中的空余元素用char类型的默认值填充,最终将value数组指向扩容后的新数组
}
}
- 当
value
数组的最大容量不足以装下minimumCapacity
个字符时,则进入newCapacity()
方法对value
数组扩容
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2; // 定义新容量,先将其赋为当前value数组的长度 × 2 + 2
if (newCapacity - minCapacity < 0) { // 扩容后仍旧装不下minCapacity个字符
newCapacity = minCapacity; // 将minCapacity赋给新容量
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) // 不清楚什么情况下newCapacity会小于等于0
? hugeCapacity(minCapacity)
: newCapacity; // 绝大多数情况下返回新容量
}
- 确保容量足够后进入
String
类的getChars()
方法
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
// srcBegin = 0, srcEnd = len, dst = value, dstBegin = count
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) { // 什么情况下会大于value.length,传进来的srcEnd就是调用该getChars()方法的字符串对象的长度,按理说应该相等才对。猜测:传入的srcEnd值有误
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
// System.arraycopy(src, srcPos, dest, destPos, length)
// src:源数组
// srcPos:源数组的起始位置
// dest:目标数组
// destPos:目标数组的起始位置
// length:拷贝的长度
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
// value是String类的final属性value,其中存储的是调用getChars()方法的字符串对象的各个字符
// scrBegin是String类的final属性value数组的起始拷贝位置
// dst是StringBulider类中的属性value数组,该arraycopy()方法的目的是将String类的final属性value数组的内容拷贝至StringBulider类中的属性value数组
// desBegin是StringBulider类中的属性value数组起始拷贝位置
// srcEnd - srcBegin是拷贝长度,问题是为什么不能直接用srcEnd,也就是传入的len?这是String类的方法,可以处理任何情况下的字符拷贝,不是单独为append()方法写的,它有它的独立性
// 将调用该arraycopy()方法的字符串对象中的value数组中的字符依次拷贝到传入的StringBuilder类对象的value数组(就是此处的dst)中,String对象的value数组拷贝的起始下标为0,StringBuilder对象的value数组拷贝的起始下标为count;拷贝长度为String对象的value数组的长度,即传入getChars()方法的len
}