StringBuilder的容量capacity变化规则

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);
}

// StringBuilder的父类AbstractStringBuilder
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();

    //调用该方法,确定最终容量Capacity
    ensureCapacityInternal(count + len);

    str.getChars(0, len, value, count);
    count += len;
    return this;
}

既然找到了方法,那就看看容量的具体变化规则吧:
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    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) // overflow
            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    内容总长度

--------------------- 
作者:cuncaojin 
来源:CSDN 
原文:https://blog.csdn.net/cuncaojin/article/details/78925234 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值