StringBuilder类的append方法及其扩容机制

StringBuilder类的append()方法

  1. 进入主方法
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()方法,并打印该对象的内容
    }
}
  1. StringBuilder类的两个重要属性
/**
 * The value is used for character storage.
 */
char[] value; // value数组用于储存字符

/**
 * The count is the number of characters used.
 */
int count; // count用于记录当前字符数组中的字符个数
  1. 进入append()方法
@Override
public StringBuilder append(String str) {
    super.append(str); // 调用其父类AbstractStringBuilder的append()方法
    return this; // 返回当前调用该方法的StringBuilder对象,相当于直接修改当前对象
}
  1. 进入其父类AbstractStringBuilderappend()方法
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; // 返回当前调用该方法的对象
}
  1. 当传入的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; // 返回当前调用该方法的对象
}
  1. 当传入的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数组指向扩容后的新数组
    }
}
  1. 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; // 绝大多数情况下返回新容量
}
  1. 确保容量足够后进入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
}
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值