AbstracStringBuilder
是StringBuilder
和 StringBuffer
的父类。前面咱们讲到String
是一个不可变的字符串。而StringBuilder
和 StringBuffer
则是对String
的一个补充,它们是可变的。先来看AbstractStringBuilder
的定义java
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
}
复制代码
从类名上就能够看出来它是一个抽象方法。而且实现了Appendable
以及Appendable
接口中的append
方法。使用了char[]
来保存值,而两个构造函数也是子类所必需要实现的,用于初始化 char[]
的大小。安全
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
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;
}
复制代码
对于扩容,须要确保传入的capacity
大于目前的value
的长度,且小于Integer.MAX_VALUE
(0x7fffffff)。在这个方法中首先把容量扩大为原来的容量乘2加2,若是此时仍小于指定的容量,那么就把新的容量设为minCapacity
。而后判断是否溢出,若是溢出了,把容量设为MAX_ARRAY_SIZE(Integer.MAX_VALUE-8)
app
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;
}
//String.class
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
复制代码
对于 append
方法有不少重载。对于每种重载方法的内部实现大概能够分为下面几步:函数
append
的值为有效的。若是是字符串,那么值若是为 null
,则会append
一个null
字符串,若是是long
或int
的值是小于最小值,那么会append
一个固定值ensureCapacityInternal
方法会将当前的char[] value
值复制到一个新的char[] value
中。getChars
方法将append
的值追加到扩容的value
后StringBuilder & StringBuffer
都实现了 AbstractStringBuilder
接口。他们最大的不一样就是StringBuilder
是线程不安全的,而StringBuffer
是线程安全的。因此它们的属性和方法大体都是同样的,只是StringBuffer
的部分方法上添加了Synchronized
关键字来保证线程的安全。性能
//StringBuffer.class
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
复制代码
在StringBuilder
中没有synchronized
这个关键字。对于StringBuilder & StringBuffer
的大部分都是调用的父类的方法,只是最后多了一个 return this
。ui
上面的代码咱们发现有这么一行代码toStringCache=null
,咱们来看看它的定义this
/** * A cache of the last value returned by toString. Cleared * whenever the StringBuffer is modified. */
private transient String toStringCache;
复制代码
根据注释,咱们能够知道这个toStringCache
是用来缓冲最后一次 toString
的值,若是StringBuffer
被修改了的话,那么toStringCache
就会被清空。接着再来看看 toString
方法spa
public synchronized String toString() {
if (toStringCache == null) {
return toStringCache =
isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}
return new String(toStringCache);
}
复制代码
当调用toString
方法的时候,若是toStringCache
为null
的话,那么就会调用StringXXX.newString
方法。若是不为null
的话,直接返回toStringCache
。而StringXXX.newString
的实现以下:线程
public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len),
LATIN1);
}
复制代码
能够发现它实际上是一个copy的操做。也就是说若是toStringCache
存在的话,就不须要再次进行copy。直接返回toStringCache
,这样就能够减小没必要要的消耗,提高性能。code