扩容原理_StringBuffer的扩容原理是什么?

本文介绍了Java中的StringBuffer类,它是可变长度的字符串类,用于提高字符串拼接效率。StringBuffer线程安全,适合多线程环境。文章详细讲解了StringBuffer的构造方法、扩容原理,当现有容量不足以容纳追加数据时,它会通过Arrays.copyOf()方法进行扩容,每次扩容容量扩大为原来的2倍加2。
摘要由CSDN通过智能技术生成

 我是小羊同学,一个长期在二线城市工作的程序员

在Java中,String是一个常量,一旦创建其值后不能更改但可以共享。

如果我们把多个字符串进行连接(拼接)操作,就会开辟很多空间,从而造成了大量内存空间的浪费。

为了解决这个问题,我们需要用到StringBuffer类和StringBuilder类。

这两个类可牛逼了,它们都是可变长度的字符串类,在字符串的拼接处理上大大提高了效率。

一、StringBuffer与StringBuilder的区别

共同点:底层数据结构都是char类型的数组,都是可变的字符串。

不同点:StringBuffer线程同步的安全性高,但多线程操作时效率低。StringBuilder线程不同步,进行多线程操作时,安全性低,但效率高。

因为这两个类的用法都类似,所以我就以StringBuffer类为例来讲解。

二、StringBuffer类的定义

StringBuffer类的部分源码:

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

从源码中可以看出,StringBuffer是一个用final修饰的最终类,继承了父类AbstractStringBuilder类,实现了Serializable接口和CharSequence接口,说明具备了两种能力。

三、四个构造方法

StringBuffer类的部分源码:

public StringBuffer() {        super(16);    }public StringBuffer(int capacity) {        super(capacity);    }public StringBuffer(String str) {        super(str.length() + 16);        append(str);    }public StringBuffer(CharSequence seq) {        this(seq.length() + 16);        append(seq);    }

重点讲下这两个构造方法:

构造方法:StringBuffer()

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

构造方法:StringBuffer(String str)

方法描述:构造一个初始化为指定字符串内容的字符串缓冲区,初始容量为str.length() + 16。

实例:

package cn.tkr.demo;public class MyStringBuffer {    public static void main(String[] args) {                StringBuffer sb1 = new StringBuffer();        System.out.println("sb1字符缓冲区的容量:" + sb1.capacity()); //获取当前StringBuffer的容量        StringBuffer sb2 = new StringBuffer("LoveJava");        System.out.println("sb2字符缓冲区的容量:" + sb2.capacity()); //获取当前StringBuffer的容量    }}

运行结果:

sb1字符缓冲区的容量:16sb2字符缓冲区的容量:24

实例分析:调用无参数构造函数,sb1字符缓冲区的初始容量为16,调用有参数构造函数,初始容量为字符串的长度(8) + 16,所以初始容量为24。

四、StringBuffer的常用方法
返回值类型方法名称描述
intlength()获取当前StringBuffer中的字符的个数
intcapacity()获取当前StringBuffer的容量
intindexOf(String str) 查找某个字符串str在StringBuffer中的索引位置,找到返回索引,找不到返回-1
StringBufferappend(…)将指定的参数的字符串追加到序列中
StringBufferdelete(int start, int end)从start的位置开始删除字符,一直删除到索引为end的位置(包含start,不包含end)
voidsetCharAt(int index,char c)使用字符c替换指定的索引index位置上的字符

注:append(...)中的...代表各种类型的参数,如append(int i)、append(char c)、append(String str)等

五、StringBuffer的扩容原理

扩容原理:

StringBuffer的底层数组结构用的是char类型的数组。

所以,当我们使用StringBuffer对象的append(...)方法追加数据时,如果char类型数组的长度无法容纳我们追加的数据,StringBuffer就会进行扩容。

扩容时会用到Arrays类中的copyOf(...)方法,每次扩容的容量大小是原来的容量的2倍加2。

注:copyOf(...)中的...代表各种类型的参数,如

copyOf(int[] original, int newLength)、copyOf(char[] original, int newLength)等

实例源码分析:

假设我现在调用了append(String str)方法,追加了一个字符串(char类型数组的长度无法容纳的字符串)。

append(String str)方法源码:

public synchronized StringBuffer append(String str) {        toStringCache = null;        super.append(str);        return this;    }

方法中通过super.append(str)调用了父类的append(String str)方法。

父类的append(String str)方法源码:

public AbstractStringBuilder append(String str) {        if (str == null)            return appendNull();        int len = str.length();        ensureCapacityInternal(count + len);        str.getChars(0, len, value, count);        count += len;        return this;    }

重点来了,这里的ensureCapacityInternal(count + len)就是一个扩容相关的方法,变量count是一个全局变量,并没有实际的值,变量len是我们追加进来的字符串的长度。

也就是说,我们追加进来的字符串的长度会传递给ensureCapacityInternal(int minimumCapacity)方法。

再来看看ensureCapacityInternal(int minimumCapacity)方法的源码:

private void ensureCapacityInternal(int minimumCapacity) {        // overflow-conscious code        if (minimumCapacity - value.length > 0) {            value = Arrays.copyOf(value,                    newCapacity(minimumCapacity));        }    }

其中,minimumCapacity指我们追加进来的字符串的长度,value是一个全局的char类型的数组名。

也就说,value.length指数组的长度,那如果(minimumCapacity - value.length > 0)这个条件成立,也就意味着,char类型数组的长度无法容纳我们追加的字符串的长度。

这时,就需要使用Arrays类中的copyOf(char[] original, int newLength)方法进行扩容。

方法:

copyOf(char[] original, int newLength)

描述:复制指定的数组,截断或使用相应的默认值进行填充

该方法的第一个参数是源数组名,所以要传递的是value。

第二个参数是新数组长度,新数组长度的值是通过newCapacity(int minCapacity)方法来计算并返回的值。

newCapacity(int minCapacity)方法的源码:

private int newCapacity(int minCapacity) {        // overflow-conscious code        int newCapacity = (value.length << 1) + 2;        if (newCapacity - minCapacity < 0) {            newCapacity = minCapacity;        }        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)            ? hugeCapacity(minCapacity)            : newCapacity;    }

这个方法会返回一个新的容量大小(即新数组长度),每次扩容的容量大小是原来的容量的2倍加2。

六、总结

以上是我分享给大家的关于StringBuffer类的一些总结。如果觉得还不错的话,就送我一个在看吧!如果本文对你有用的话,也欢迎收藏哦!

cc9c175191c9b6571f318c2060856a9a.png

end

a46e6b86d95002d1534ddd2684764bc9.png dc9615a92c31c2a4c5d81c5d274526ac.png

MySQL中的索引为什么使用B+tree实现?

106f9f67f4b349505b2d3485e718855f.png

时间复杂度和空间复杂度

1fa72d5666c6e302dde3ea4148b706a7.png

37岁未婚女程序员,年薪60万,却对工作生活感到迷茫

4e3042b30f6fb9b41d16ef9e5c2d25ed.png

秒杀系统的艺术

*版权声明:转载文章和图片均来自公开网络,版权归作者本人所有,推送文章除非无法确认,我们都会注明作者和来源。如果出处有误或侵犯到原作者权益,请与我们联系删除或授权事宜。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值