StringBuilder的容量capacity变化规则

2022-07-15 11:15:40

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----016----1634----1970----3570----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----1635----35

问题

运行结果1运行结果2都能看出,StringBuilder的容量变化规律貌似不再是网上很多人所说的那样(容量默认为16,追加数据时,如果容量不够,则每次2倍整地扩容,直到容量不小于StringBuilder的长度值为止。)
那容量的变化规律到底是什么样的呢?接下来进入源码进行分析。

测试代码 1 的源码分析

publicStringBuilder() {super(16);
}// StringBuilder的父类AbstractStringBuilderabstract 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 =newchar[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 AbstractStringBuilderappend(String str) {if (str ==null)return appendNull();int len = str.length();//调用该方法,确定最终容量Capacity
    ensureCapacityInternal(count + len);

    str.getChars(0, len, value, count);
    count += len;returnthis;
}
  • 既然找到了方法,那就看看容量的具体变化规则吧:
privatevoidensureCapacityInternal(int minimumCapacity) {// overflow-conscious codeif (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)// overflowthrownew 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变化规则为:

  1. 初始值为16;
  2. 如果minimumCapacity(新添加的数据长度和已有数据长度的和)小于当前容量Capacity,则添加数据后容量Capacity不变;
  3. 如果minimumCapacity(新添加的数据长度和已有数据长度的和)大于当前容量Capacity,但minimumCapacity**小于**当前容量Capacity的2倍加2,则添加数据后容量Capacity变为上次容量的2倍加2;
  4. 如果minimumCapacity(新添加的数据长度和已有数据长度的和)大于当前容量Capacity的2倍加2,则添加数据后容量Capacity即为minimumCapacity(新添加的数据长度和已有数据长度的和)。
初始值原容量 < 总内容 <= 2 * 原容量 + 2总内容 > 2 * 原容量 + 2
162 * 原容量 + 2内容总长度
  • 作者:cuncaojin
  • 原文链接:https://blog.csdn.net/cuncaojin/article/details/78925234
    更新时间:2022-07-15 11:15:40