String和StringBuffer和StringBuilder的区别及扩容

本文探讨了String(不可变)、StringBuffer(线程安全,缓存优化)和StringBuilder(线程不安全,效率高)之间的区别,包括内存使用、线程安全性和扩容机制。重点讲述了它们在操作字符串时的性能差异和适用场景。
摘要由CSDN通过智能技术生成

String和StringBuffer和StringBuilder的区别及扩容

1.String类

我前面写了一篇文章详细介绍了String,这里就不再赘述了。感兴趣的小伙伴可以点击此链接String详解

2.StringBuffer类

StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
StringBuffer被final修饰不可被继承

 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

StringBuffer是线程安全的,它的绝大多数方法都做了同步处理(被synchronized修饰)

 @Override
    public synchronized StringBuffer append(double d) {
        toStringCache = null;
        super.append(d);
        return this;
    }
    @Override
    public synchronized StringBuffer replace(int start, int end, String str) {
        toStringCache = null;
        super.replace(start, end, str);
        return this;
    }

toString方法会进行对象缓存,减少元素复制开销。

    @Override
    public synchronized String toString() {
        if (toStringCache == null) {
        //进行对象缓存
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

3.StringBuilder类

StringBuilder类也代表可变字符串对象。实际上,StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同。
不同的是:StringBuffer是线程安全的,没有同步处理(没有被synchronized修饰),所以它比StringBuffer 要快。

@Override
    public StringBuilder append(double d) {
        super.append(d);
        return this;
    }
    @Override
    public StringBuilder replace(int start, int end, String str) {
        super.replace(start, end, str);
        return this;
    }

toString方法直接返回一个Sting对象

 @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

4.StringBuffer和StringBuilder的扩容

StringBuffer和StringBuilder的扩容机制是一样的。这里以StringBuilder为例
StringBuilder对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。
在没有传参的情况下默认初始容量是16。

  public StringBuilder() {
        super(16);
    }

指定分配给该对象的实体的初始容量

 public StringBuilder(int capacity) {
        super(capacity);
    }

有参数的情况下,初始容量是16+字符串的长度,并且是用append()方法追加的字符

public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

测试

 StringBuilder b = new StringBuilder("hello");
        System.out.println(b.length());//长度为5
        System.out.println(b.capacity());//容量为21

如果要添加的数据底层数组存不下了,那就需要扩容底层的数组。

  private int newCapacity(int minCapacity) {
        // 扩容为原来的两倍加2
        int newCapacity = (value.length << 1) + 2;
        //如果还是放不下,那就直接扩容到它需要的长度
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

通过源码我们发现它是这么扩容的 int newCapacity = (value.length << 1) + 2。<< 是位运算符,相当于乘以2,即原来的位数扩容为原来的两倍,然后再加2;这个时候如果还是放不下,那就直接扩容到它需要的长度 newCapacity = minCapacity。扩容好后将原有数组中的元素复制到新的数组中。
可能有小伙伴会有疑问,为什么扩容是2倍+2?为什么要+2?
请注意传入参数int,意味着这里传入参数可以是0,那么在参数是0的情况下,0<<1运算结果也是0,那么在初始化数组的时候必然会报错,所以作为设计的安全性考虑,这里防止出现报错,选择了+2。
参考链接

总结:string和stringBuffer和stringbuilder的区别

  1. String 是字符串常量,当创建之后即不能更改。底层使用 final char value[]。
  2. StringBuffer 是字符串变量,可通过append()、insert()、setCharAt()等方法改变。底层使用 char[] value。是线程安全的,它的绝大多数方法都做了同步处理(被synchronized修饰,toString方法会进行对象缓存,减少元素复制开销。
  3. StringBuilder 与StringBuffer基本相似,都继承和实现了同样的接口和类。不同点在于:StringBuilder方法没使用synch修饰是线程不安全的,所以它比StringBuffer要快。toString方法直接返回一个新对象,不会进行对象缓存。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值