StringBuilder源码解析

StringBuilder

StringBuilder是一个继承AbstractStringBuilder,实现SerializableCharSequence接口的类

public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
    // 此处不粘贴源码
}

初始化

1.StringBuilder

public StringBuilder(String str) {
    //调用父类构造方法创建一个定长的空数组,参数传入:字符串长度+16,看1.1
    super(str.length() + 16);
    // 向空数组中填数据,看1.2
    append(str);
}

1.1 父类AbstractStringBuilder构造方法

char[] value;// 存储字符串内容

AbstractStringBuilder(int capacity) {
    value = new char[capacity];// new一个定长的数组
}

1.2 StringBuilder.append方法

public StringBuilder append(String str) {
    super.append(str);//调用父类append方法实现,看1.2.1
    return this;
}

1.2.1 父类AbstractStringBuilder.append方法

int count;//长度计算值:记录value的长度,默认初始值:0

public AbstractStringBuilder append(String str) {
    // 判断传入的字符串是否为null
    if (str == null)
        return appendNull();
    int len = str.length();//再次获取字符串长度
    ensureCapacityInternal(count + len);//创建时,count=0,看1.2.1.1
    //调用String类的getChars方法,生成一个定长的新数组,将str的数据拷贝进value中,这一步结束后value完成赋值
    str.getChars(0, len, value, count);
    count += len;// 长度计算值+=当前数组长度
    return this;
}

1.2.1.1 父类AbstractStringBuilder.ensureCapacityInternal方法

/**
 * @param minimumCapacity append方法中传入的count+len
 * 
*/
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    // 判断传入的参数(长度)是否大于刚生成的数组长度
    if (minimumCapacity - value.length > 0) {
        /**
         * 若大于,证明刚生成的数组容量不满足要求
         * 1.调用newCapacity计算扩容后总量(看1.2.1.1.1)
         * 2.调用Arrays.copyOf方法,重新生成一个数组,并将原数组数据拷贝进去
         * */ 
        value = Arrays.copyOf(value,newCapacity(minimumCapacity));
    }
}

1.2.1.1.1 newCapacity 获取“待扩容的数组长度”

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 2^31-1 -8

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2;// 计算扩容后的数组长度,将原来的数组扩容1倍多2
    if (newCapacity - minCapacity < 0) {
        // 若“待扩容后的数组长度”还是小于“要求最小扩容量”,则直接使用“要求最小扩容量”作为“待扩容后的数组长度”
        newCapacity = minCapacity;
    }
    /**
     * 再一次验证,这次时为了防止容量越界,若MAX_ARRAY_SIZE都小于“待扩容后的数组长度”,看1.2.1.1.1.1
     * */ 
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

Arrays.copyOf 方法

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

1.2.1.1.1.1 AbstractStringBuilder.hugeCapacity方法

/**
 * 取“待扩容后的数组长度”,在“待扩容后的数组长度”大于MAX_ARRAY_SIZE成立时被调用
 * 1.验证“待扩容后的数组长度”是否大于Integer.MAX_VALUE(2^31-1),若大于证明“待扩容后的数组长度”超界了,直接抛异常
 * 2.上一步验证通过,接着判断“待扩容后的数组长度”和MAX_ARRAY_SIZE(2^31-1 -8)谁大,取最大者
*/
private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}

由源码可知

  1. StringBuilder的大量操作都是由其父类AbstractStringBuilder实现的
  2. StringBuilder是线程不安全类
  3. StringBuilder有容量限制,且当前容量不满足要求时会重新创建char[],都由父类AbstractStringBuilder实现;网上都在说StringBuilder动态扩容,这种说法也对也不对,对是因为它在不满足要求时的确扩容了,而且扩容量给到了原容量的1倍+2,一定程度上这会减少new char[]造成的消耗,不对是因为它不在原数组上扩容,是直接创建新char[newLenth],然后拷贝旧数组数据实现扩容
  4. StringBuilder初始化数组长度:字符串长度+16

Tips

其实在操作StringBuilder的变量时跟一跟源码,就会发现,AbstractStringBuilder实现了StringBuilder的绝大部分方法,就连存储字符串的char[] value也是由AbstractStringBuilder提供的

posted @   勤匠  阅读(21)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示