StringBuffer与StringBuilder
StringBuffer和StringBuilder都是继承自AbstractStringBuilder
它们两个的区别在于StringBuffer是线程安全的但效率低,StringBuilder是线程不安全的但高效。
StringBuffer和StringBuilder的扩容机制是一样的,因此分析一个即可,下面以StringBuffer为例。
StringBuffer与StringBuilder扩容机制
StringBuffer
的底层数组结构用的是char
类型的数组。
所以,当我们使用StringBuffer
对象的append(...)
方法追加数据时,如果char类型数组的长度无法容纳我们追加的数据,StringBuffer
就会进行扩容。
扩容时会用到Arrays
类中的copyOf(...)
方法,
StringBuffer 的无参构造初始容量为:16,
StringBuffer 的有参构造初始容量为:字符串参数的长度+1
有参和无参扩容方法都一样的。都是从当前容量开始扩容
一次追加长度超过当前容量,则会按照 当前容量*2+2 扩容一次
一次追加长度不仅超过初始容量,而且按照 当前容量*2+2 扩容一次也不够,其容量会直接扩容到与所添加的字符串长度相等的长度。之后再追加的话,还会按照 当前容量*2+2进行扩容
实例源码分析:
假设我现在调用了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)
方法进行扩容。