关于StringBuilder和StringBuffer扩容的问题

首先,查看一下二者的继承体系,都继承自抽象类AbstractStringBuilder

下面是AbstractStringBuilder类的有参数构造器

AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
在新建StringBuilder和StringBuffer的会后都会调用父类的构造器,默认长度为16

public StringBuilder() {
        super(16);
    }
public StringBuffer() {
        super(16);
    }
有参数构造器
public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }
再说他他们的扩容:

使用append()方法在字符串后面追加方法的时候,如果长度超过了字符串的存储空间,就需要扩容,扩容的方式就是构建新的字符串将新的复制过去,在进行字符串append添加的时候,会先计算添加后字符串大小,传入一个方法:ensureCapacityInternal 这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容:

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);
    }
先尝试将容量夸大至2倍+2,如果还是不够,则直接扩容至需要的大小,


最后上测试代码

public static void main(String[] args) {
        //1:调用无参数构造器
        StringBuffer str = new StringBuffer();
        str.append("12345");
        System.out.println(str.capacity());//16
        System.out.println(str.length());//5
        str.append("67890123456");
        System.out.println(str.capacity());//16
        System.out.println(str.length());//16
        str.append("1");
        System.out.println(str.capacity());//34
        System.out.println(str.length());//17
        //2:调用有参数构造器
        str = new StringBuffer("123");
        System.out.println(str.capacity());//19
        System.out.println(str.length());//3
    }



### Java 中 `StringBuffer` `StringBuilder` 的扩容机制 当向 `StringBuffer` 或 `StringBuilder` 对象追加数据时,如果现有容量不足以容纳新的字符序列,则会触发扩容操作。扩容过程涉及创建一个新的更大的数组来存储更多的字符。 #### 容量计算方式 对于这两种类,在执行扩容时都会遵循相似的原则: - 当前容量不足时,默认情况下新容量将是旧容量的两倍加上2个单位[^5]。 ```java // 计算新容量大小 int newCapacity = (oldCapacity << 1) + 2; ``` 这种策略可以减少频繁分配内存带来的开销,并且能够有效地利用空间。 #### 扩容的具体实现细节 具体到源码层面,无论是 `StringBuffer` 还是 `StringBuilder` 都依赖于其父类 `AbstractStringBuilder` 来完成实际的扩容逻辑[^2]。以下是简化版的扩容流程说明: 1. **判断是否需要扩容** 如果当前缓冲区长度小于所需最小容量,则进入下一步; 2. **确定目标容量** 新的目标容量等于原容量乘以二再加二,除非指定了更具体的增长规则; 3. **重新分配内存并复制原有内容** 创建一个更大尺寸的新字符数组并将原来的数据拷贝过去; 4. **更新对象状态** 将引用指向新的大数组,并调整内部变量反映最新的情况。 通过这种方式,即使不断添加更多字符也不会轻易遇到性能瓶颈问题。 #### 实际案例分析 考虑下面的例子,展示了如何动态改变 `StringBuilder` 的内容及其背后的自动扩容行为[^4]: ```java public class Method_EX { public static void main(String[] args) { // 初始化 StringBuilder 并设置初始值 "12345" StringBuilder sb = new StringBuilder("12345"); // 输出原始字符串 System.out.println("当前字符串 = " + sb); // 反转字符串顺序 sb.reverse(); System.out.println("颠倒后的字符串 = " + sb); // 向末尾追加多个不同类型的内容 sb.append(123).append("哈哈哈").append(666.666f).append("牛逼!"); System.out.println("增加后的字符串 = " + sb); // 清除所有字符 sb.delete(0, sb.length()); System.out.println("全部删光光!当前字符串 = " + sb); } } ``` 在这个例子中,随着连续调用 `append()` 方法,每当超出当前可用的空间限制就会发生一次隐式的扩容动作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值