前言
了解一些java底层设计最直接最准确的的方法就是源码了。
StringBuffer和StringBuilder都继承自AbstractStringBuilder。jdk1.8中源码位于rt.jar/java/lang/
路径下。
相关源码
初始的空闲容量都是16,当调用append方法时调用的都是super.append即AbstractStringBuilder
中方法,所以扩容机制相同。
// StringBuffer.java
public StringBuffer() {
super(16);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
//StringBuilder.java
public StringBuilder() {
super(16);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
通过append方法中的ensureCapacityInternal
方法可以看出当追加后超出容量会触发扩容,通过newCapacity
获得新容量。
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
计划扩容为2*n+2
,n为扩容前容量,如果追加后长度超出则扩容为n+count
,count为追加长度。由此可见下次append还会触发扩容机制。所以在设计时应该避免,最好能在初始时设置一个合理的容量。
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;
}
最大容量为Integer.MAX_VALUE
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
另外还提供了方法用于用户测试调用的扩容方案,在追加超长字符串时可减少多次自动扩容的花销。
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
此外StringBuffer和StringBuilder的区别就在于StringBuffer的操作使用synchronized
关键字加了锁,是线程安全的。
结论
StringBuffer和StringBuilder扩容都是通过共同父类AbstractStringBuilder
实现的。
初始为len+16
或自设置。后续扩容k>2*n+2?k:2*n+2
。