Java基础--String、StringBuffer和StringBuilder

之前我们在另一篇博客讲过,String是被final修饰的,是一个不可变对象。(点击这里查看)我们如果要修改String的内容,就只能通过重新new一个对象来实现。毫无疑问,这是非常耗内存的,当我们需要不断的更改String对象的内容时,我们的内存空间很容易溢出。因此,我们有了StringBuffer和StringBuilder这两个替代品。

StringBuffer

StringBuffer类继承自AbstractStringBuilder抽象类,实现了Serializable序列化接口和CharSequence接口。

StringBuffer的构造方法

构造方法
Constructor and Description
StringBuffer()

构造一个没有字符的字符串缓冲区,初始容量为16个字符。

StringBuffer(CharSequence seq)

构造一个包含与指定的相同字符的字符串缓冲区 CharSequence 。

StringBuffer(int capacity)

构造一个没有字符的字符串缓冲区和指定的初始容量。

StringBuffer(String str)

构造一个初始化为指定字符串内容的字符串缓冲区。

StringBuffer的常用方法

StringBufferappend(String str)

将指定的字符串附加到此字符序列。

charcharAt(int index)

返回 char在指定索引在这个序列值。

StringBufferdelete(int start, int end)

删除此序列的子字符串中的字符。

intindexOf(String str)

返回指定子字符串第一次出现的字符串内的索引。

StringBufferinsert(int offset, String str)

将字符串插入到此字符序列中。

intlength()

返回长度(字符数)。

Stringsubstring(int start)

返回一个新的 String ,其中包含此字符序列中当前包含的字符的子序列。

Stringsubstring(int start, int end)

返回一个新的 String ,其中包含此序列中当前包含的字符的子序列

StringBuffer初始化及扩容机制

StringBuffer与String最大的不同在于StringBuffer是可变的对象,它可以根据要存储的字符串长度来改变自己的容量,这离不开它本身的扩容机制。首先我们通过StringBuffer的构造函数来了解它不同的初始化方式。

  • StringBuffer():StringBuffer的初始容量可以容纳16个字符,当该对象的实体存放的字符长度大于16时,实体容量就自动增加。StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。
  • StringBuffer(int size):可以指定分配给该对象的实体的初始容量参数为参数size指定的字符个数。当该对象的实体存放的字符序列的长度大于size个字符时,实体的容量就自动的增加。以便存放所增加的字符。
  • StringBuffer(String s):可以指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符。当该对象的实体存放的字符序列长度大于size个字符时,实体的容量自动的增加,以便存放所增加的字符。

接下来我们来通过append()方法来了解它的扩容方法。

使用append()方法在字符后面追加东西的时候,如果长度超过了该字符串存储空间大小了就需要进行扩容:构建新的存储空间,将旧的复制过去。我们可以从它的源码很容易看出来这个过程:

//AbstractStringBuilder的方法
public AbstractStringBuilder append(String str) {
        //判空
        if (str == null) str = "null";
        int len = str.length();

        //判断是否足够存储str字符串,若不够则调用expandCapacity方法进行扩容
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
}



//判断是否需要扩容
private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
    }



//扩容方法
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);
    }



//将字符串复制过去 String类的方法
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }


        /*  srcBegin - 以此偏移开始复制。
            srcEnd - 在此偏移处停止复制。
            dst - 将数据复制到的数组。
            dstBegin - 偏移到 dst 。*/


        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

从源码我们可以更加清晰的了解StringBuffer的扩容过程。当我们进行字符串append时,会先计算添加后字符串大小,传入一个方法ensureCapacityInternal()进行扩容判断,需要扩容则调用expandCapacity方法进行扩容。尝试将新容量扩为原大小的2倍+2,然后再进行一次if判断,容量如果不够,直接扩充到需要的容量大小,即更新后字符串的大小。

StringBuilder和StringBuffer

StringBuilder所继承的抽象类和实现的接口都与StringBuffer一模一样,他们两者的方法和功能完全是等价的。只是StringBuffer中的方法大都采用synchronized关键字进行修饰,因此是线程安全的,而StringBuilder没有,可以被认为是线程不安全的。由于使用了synchronized关键字,所以在单线程程序下,StringBuilder效率更快。

总结

  1. 从字符串底层存储对象来看,String是不可变对象,而StringBuilder和StringBuffer是可变长度对象。
  2. 从线程安全来看,StringBuffer是线程安全对象,因为很多方法被synchronized方法修饰,而String和StringBuilder是线程不安全的。
  3. 从效率来看,大部分情况下StringBuilder>StringBuffer>String.

参考:https://blog.csdn.net/longfulong/article/details/78700239

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值