StringBuilder类的源码和StringBuffer类除了线程是否同步外,其他并无差别,而他们都有一个共同的父类AbstractStringBuilder ,真正实现核心逻辑的是AbstractStringBuilder 。
源码分析
1、StringBuilder类
/**
* StringBuilder继承了AbstractStringBuilder
* 实现了Serializable序列化接口,表示对象可序列化,实现了CharSequence字符序列接口,表示可进行字符的相关操作
**/
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
// 与StringBuffer类的构造器一样,通过super()调用父类构造器,append()调用的也是父类ASB的构造器
public StringBuilder() { super(16);}
public StringBuilder(String str) { super(str.length() + 16); append(str);}
public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq);}
public StringBuilder(int capacity) { super(capacity);}
// append()/insert()/deleteCharAt()/delete()/indexOf()/lastIndexOf()/replace()/subString()/reverse()等除了不是同步synchronized的,其他与StringBuffer类一样
......;
}
小结一下:
- StringBuilder类的源码可以看出:除了操作字符串线程不安全,其他的特点与StringBuffer类一模一样。
2、AbstractStringBuilder类
AbstractStringBuilder类是操作可变字符串类(如StringBuffer、StringBuilder)的父类,而子类中的append()/insert()/deleteCharAt()/delete()/reverse()等核心方法的逻辑基本是在父类中实现的。
构造方法
构造器很简单,维护的是一个字符数组来存储字符串。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value; //存储字符串的字符数组
int count; //字符数组中元素的格式
// 将字符串存储在字符数组中
AbstractStringBuilder() {}
AbstractStringBuilder(int capacity) {value = new char[capacity];}
}
append()方法
以引用对象类型(如Object、CharSequence、String、StringBuffer、AbstractStringBuilder)作为追加的内容为例,基本步骤如下:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull(); //1.对象判空检查
int len = str.length();
ensureCapacityInternal(count + len); //2.确保初始化容量大小
//3.本质是System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
str.getChars(0, len, value, count);
count += len;
return this; //4.返回当前对象
}
在StringBuilder对象创建后去追加内容,为什么要确保初始化容量大小?通过构造器创建的StringBuilder对象默认容量大小为16,或者去指定容量大小,而继续追加内容时需要保证追加的内容不会超过容量大小,如果超过了则需要进行扩容处理。
扩容涉及到的方法有下面三个,基本逻辑就是:
- 追加的字符串长度 + 原有的字符串长度 如果超过字符数组的指定容量大小,会通过newCapacity()增加容量大小;
- 每次扩容大小为:原字符数组大小*2 + 2 ,如果扩容后容量仍小于追加的字符串长度 + 原有的字符串长度,将扩容后容量默认为字符串长度 + 原有的字符串长度;
- 字符串并不是无上限追加的,最大为Integer类型大小,极限的取值区间为:[Integer.MAX_VALUE - 8, Integer.MAX_VALUE) 。
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
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;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
追加的内容为基本类型也是需要进行是否扩容处理,insert()方法实现的字符串追加,replace()方法实现的字符串替换,也是上面这些步骤。
delete()方法
删除的核心:就是将修剪后的数组copy到目标数组,更新字符数组元素的个数
public AbstractStringBuilder delete(int start, int end) {
// 参数判断
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
// 修剪后的数组copy到目标数组
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len; // 删除字符的个数
}
return this;
}
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
count--;
return this;
}
看到这儿,应该会发现一个有趣的现象,操作字符串底层是通过操作字符数组来实现的,很多处用到了System.arraycopy()方法,它作用是将原数组拷贝到目标数组,从而实现数组的替换。