1.StringBuffer和StringBuilder简介
在Java中,我们除了可以通过String类创建和处理字符串之外,还可以使用StringBuffer和StringBuilder类来处理字符串。
其中,String类定义的字符串内容不可变,所以String属于不可变字符串。
而StringBuffer和StringBuilder定义的字符串内容可变,这两者属于可变字符串,并且StringBuffer和StringBuilder,对字符串的处理效率比String类更高。
StringBuffer和StringBuilder其实都是继承自AbstractStringBuilder二者也都实现了java.io.Serializable, CharSequence接口
StringBuilder和StringBuffer最大的不同在于,StringBuilder的各个方法都不是线程安全的(不能同步访问),在多线程时可能存在线程安全问题,但StringBuilder的执行效率却比StringBuffer快的多。
2.StringBuilder的append过程
1)查看StringBuilder的append()方法
例如传入参数为int类型,返回的是this,在此并没有new一个新的对象
char[] value;
@Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
2)查看super.append(i)方法
ensureCapacityInternal()确保字符数组长度足够,然后将i添加进字符数组中
仍返回的是this
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
}
3)查看ensureCapacityInternal()函数
传入的spaceNeeded参数为append后保存字符串的字符数组的长度。在函数中,如果如果原本的字符数组长度过短,就会执行Arrays.copyOf()重新开辟一个容量足够的内存空间,将字符数组复制进去,从新赋值给value
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
4)查看newCapacity(minimumCapacity)
其返回的int为新开辟空间的长度,一般为value.length*2+2,如果空间还不够,就直接将append后的长度赋值给newCapacity ,如果newCapacity 不合法(过大或者超过了Integer的最大值变为了负数),就返回hugeCapacity(minCapacity)函数所返回的合法的长度,newCapacity合法就返回newCapacity
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
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;
}
5)查看hugeCapacity(minCapacity),如果minCapacity过大,抛出异常,返回minCapacity 和 MAX_ARRAY_SIZE中的最大值
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
3.StringBuffer的append过程
1)查看StringBuffer的append()方法
toStringCache为新加入的内容的缓冲区
例如传入参数为int类型,返回的是this,在此并没有new一个新的对象
private transient char[] toStringCache;
char[] value;
@Override
public synchronized StringBuffer append(int i) {
toStringCache = null;
super.append(i);
return this;
}
2)查看super.append(i)方法
ensureCapacityInternal()确保字符数组长度足够,然后将i添加进字符数组中
仍返回的是this
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
}
3)查看ensureCapacityInternal()函数
传入的spaceNeeded参数为append后保存字符串的字符数组的长度。在函数中,如果如果原本的字符数组长度过短,就会执行Arrays.copyOf()重新开辟一个容量足够的内存空间,将字符数组复制进去,从新赋值给value
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
4)查看newCapacity(minimumCapacity)
其返回的int为新开辟空间的长度,一般为value.length*2+2,如果空间还不够,就直接将append后的长度赋值给newCapacity ,如果newCapacity 不合法(过大或者超过了Integer的最大值变为了负数),就返回hugeCapacity(minCapacity)函数所返回的合法的长度,newCapacity合法就返回newCapacity
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
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;
}
5)查看hugeCapacity(minCapacity)
如果minCapacity过大,抛出异常,返回minCapacity 和 MAX_ARRAY_SIZE中的最大值
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
总结
StringBuffer和StringBuilder扩容机制的基本规则如下:
● 如果一次追加的字符长度超过了当前设置的容量,则会按照 当前容量*2+2 进行扩容;
● 如果一次追加的长度不仅超过了初始容量,而且按照 当前容量*2+2 扩容一次还不够,其容量会直接扩容到与所添加字符串长度相等的长度;
● 之后如果还要再追加新的字符内容,依然会按照 当前容量*2+2 进行扩容。