深入源码分析StringBuffer和StringBuilder
众所周知,StringBuffer是线程安全,StringBuilder线程不安全,所以StringBuilder性能略高,那还有没有其他细节上的特性呢?让我们从源码分析
StringBuffer和StringBuilder都继承了AbstractStringBuilder类
AbstractStringBuilder类关键源码
- 抽象类,是Stringbuilder和StringBuffer的父类,有两个主要的属性:
- 字符数组value,用来存放字符串
- int类型的count值,用于
计算存储使用的字符数量
,并且每次增删改都会更新该count值 - capacity方法才是返回字符数组的总长度,value.length;
- 该类中的大部分方法被其子类StringBuffer和StringBuilder所调用,其中的扩容机制是关键
1 | abstract class AbstractStringBuilder implements Appendable, CharSequence { |
ensureCapacity扩容机制
1 | //扩容机制 确保容量 |
1 |
|
append方法
1 | //append方法的重载 |
delete方法
1 | //删除一部分的字符,传入要删除段的开始下标和终止下标 |
insert方法
1 | //在对象中间插入字符串数组 |
reverse方法
1 | //反转字符串 |
substring方法
1 | //返回一个新字符串,是此字符串的一个子字符串 |
System.arraycopy
Arrays.copyOf()方法返回的数组是新的数组对象,数组拷贝时调用的是本地方法 System.arraycopy() ,原数组对象仍是原数组对象,不变,该拷贝不会影响原来的数组。
System.arraycopy() 源码如下:
1 | public static native void arraycopy(Object src, int srcPos, |
参数说明:
src:源对象
srcPos:源数组中的起始位置
dest:目标数组对象
destPos:目标数据中的起始位置
length:要拷贝的数组元素的数量
StringBuilder的关键源码
- 线程不安全,修改的方法全部都为线程不安全,是牺牲了安全用以实现性能
- 由final修饰,不能被继承,并且继承了AbstractStringBuilder类
- 重写了toString方法
- 实现了序列化接口,可序列化
- 默认初始化容量为capacity = 16 ,基本所有jdk中实现类涉及初始化容量的大小都为16,加上一点扩容机制
1 | public final class StringBuilder |
StringBuffer的关键源码
一个字符序列可变的字符串,这个StringBuffer提供了一系列的修改方法去改变字符串对象序列
- 线程安全,增删改操作方法都加了
synchronized
锁,加锁系统开销大,效率相对StringBuilder较低 - 注意:和Builder的区别有一个
transient char[] toStringCache
,toStringCache的字符数组,最后一次修改后的缓存值(字符数组保存),只要修改了value,那么就会重置,当然这个Cache是建立在线程安全之上
的,不保证线程安全就不会涉及到该Cache的操作,该toStringCache会在使用toString方法时起到提高效率的作用
1 | public final class StringBuffer |
字符串系列类的一些问题
效率问题
效率:StringBuilder > StringBuffer > String
- StringBuffer和StringBuilder都有
自动扩容
机制,增删改操作时,返回的是原来自身的对象,不会重新创建对象,不会产生很多对象垃圾 - String有两大缺点:
- 返回对象使用大量new操作,返回值均为新建的String对象,会在堆内存中产生很多垃圾;
- 虽然最终调用的是系统复制数组操作,但调用之前开销非常大,只能靠复制来解决拼接问题。
1 | public static void main(String[] args) { |
线程安全问题
- 增删改操作时,StringBuffer线程安全,StringBuilder线程不安全
使用总结
如果要操作少量的String数据可以使用用 String
不考虑线程安全问题,大量数据进行操作使用 StringBuilder
考虑线程安全问题,大量数据进行操作使用 StringBuffer