StringBuilder和StringBuffer的区别、扩容机制

1、StringBuilder和StringBuffer的区别

  • StringBuilder部分公开方法源码

  • StringBuffer部分公开方法源码

        当使用synchronized关键字对方法进行修饰时,在多线程环境下可以保证同一时间只有一个线程可以访问和修改StringBuffer对象,从而保证了数据的一致性和线程安全,但会使其的性能变差,反之StringBuilder不使用虽然线程不安全,但其性能好

2、数据结构(类型、定义)

  • 类型

    StringBuilder和StringBuffer都继承自AbstractStringBuilder类,AbstractStringBuilder内部使用一个char数组来存储字符序列,因此StringBuilder本质上是基于char数组实现的。

//StringBuilder继承AbstractStringBuilder类
public final class StringBuilder
    extends AbstractStringBuilder
    implements Serializable, CharSequence{}


//StringBuffer继承AbstractStringBuilder类
public final class StringBuffer
    extends AbstractStringBuilder
    implements Serializable, CharSequence{}
  • 定义

        在AbstractStringBuilder类中,char数组的定义如下:

3、初始化方式

  • 无参构造方法

        内部的char[ ]数组按照16的长度进行初始化

//无参构造方法内部默认为:16
public StringBuffer() {
        super(16);
    }
  • 有参构造方法

        内部的char[ ]数组按照str+length()+16的长度进行初始化

//有参构造方法内部默认为:当前传入字符串长度+16
public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}


4、二者的扩容机制

        当使用append()方法向二者中追加字符时,如果当前char数组的容量不足符,就会进行扩容操作。具体的扩容步骤如下:

  1. 计算新的容量。新容量的计算公式为:newCapacity = (value.length << 1) + 2,即原容量的2倍+2。
  2. 检查新容量是否足够。如果新容量仍然不足以容纳新追加的字符,则将新容量设置为需要的最小容量。
  3. 创建一个新的char数组,容量为新容量。
  4. 将原char数组中的内容复制到新的char数组中。
  5. 使用新的char数组替换原char数组。
// AbstractStringBuilder 类中的相关方法
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    // 存储字符的数组
    char[] value;
    // 当前字符序列的长度
    int count;
    // 数组最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    // 确保容量足够的内部方法
    private void ensureCapacityInternal(int minimumCapacity) {
        // 如果需要的最小容量大于当前数组的长度,进行扩容
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

    // 计算新容量的方法
    private int newCapacity(int minCapacity) {
        // 原容量的两倍加 2
        int newCapacity = (value.length << 1) + 2;
        // 如果新容量小于需要的最小容量,将新容量设置为需要的最小容量
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        // 判断新容量是否合理,如果不合理调用 hugeCapacity 方法处理
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
                ? hugeCapacity(minCapacity)
                : newCapacity;
    }

    // 处理超大容量需求的方法
    private int hugeCapacity(int minCapacity) {
        // 如果需要的最小容量小于 0,说明溢出了,抛出内存不足错误
        if (Integer.MAX_VALUE - minCapacity < 0) { 
            throw new OutOfMemoryError();
        }
        // 如果需要的最小容量大于最大数组容量,返回需要的最小容量,否则返回最大数组容量
        return (minCapacity > MAX_ARRAY_SIZE)
                ? minCapacity : MAX_ARRAY_SIZE;
    }
}

// StringBuffer 类调用父类方法的示例
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
    // append 方法调用 ensureCapacityInternal 确保容量
    @Override
    public synchronized StringBuffer append(String str) {
        super.append(str);
        return this;
    }
}

5、总结

  • 由于StringBuilder 和StringBuffer 两者都是继承AstractSbtringBuilder 父类,而且未使用final关键字修饰char[]数组,所以二者都是可变的。
  • StringBuilder为使用synchronized关键字修饰,StringBuffer使用了synchronized关键字修饰,所以StringBuffer线程安全但性能较差,而StringBuilder虽然不安全,但性能较好。
  • 扩容机制首先尝试将原容量扩大为2倍+2,如果这个新容量仍然不够,就会使用需要的最小容量作为最小容量。如果新容量足够,则使用新容量作为当前数组容量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joker—H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值