StringBuffer与StringBuilder的异同点
相同点
- 都是一个可变的字符序列,最主要的方法是append(),insert(),用于追加与偏移插入,可以接受任何数据类型
- 有着固定容量,默认为16,当超过最大长度之后,会进行扩容
不同点
- StringBuilder不支持线程同步,StringBuffer在所有的操作上加上了Syn锁
capacity长度增长分析
- 从
StringBuffer的append(
)函数入手
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
@Override
public synchronized StringBuffer append(int i) {
toStringCache = null;
super.append(i);
return this;
}
- 直观,点进去看父类实现
这里博主找了一个插入Int的例子,其他插入的代码类似,想看的可以到AbstractStringBuilder
类查看具体实现,这里不是我们的终点,
点进ensureCapacityInternal()
函数继续
public AbstractStringBuilder append(int i) {
int count = this.count;
int spaceNeeded = count + Integer.stringSize(i);
!!!! ensureCapacityInternal(spaceNeeded);!!!
if (isLatin1()) {
Integer.getChars(i, spaceNeeded, value);
} else {
StringUTF16.getChars(i, count, spaceNeeded, value);
}
this.count = spaceNeeded;
return this;
}
- 这里有几个常量,向自己看一看他们的具体含义的可以到
AbstractStringBuilder
查看
我们需要关注的是最后的复制value[]数组的部分,由于coder默认为0,所以新数组的长度完全由newCapacity(minimumCapacity)
函数决定,我们继续深入
这里给出AbstractStringBuilder中定义的常量含义
/**用来存储字符
* The value is used for character storage.
*/
byte[] value;
/**
* The id of the encoding used to encode the bytes in {@code value}.
*/
byte coder;
/**字符串的长度
* The count is the number of characters used.
*/
int count;
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
if (minimumCapacity - oldCapacity > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity) << coder);
}
}
4.最终我们找到了关于长度增长的具体逻辑,各位也可以自己阅读源码,博主有分析不对的地方,欢迎各位指正
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder; // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
int UNSAFE_BOUND = Integer.MAX_VALUE >> coder;
if (UNSAFE_BOUND - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > SAFE_BOUND)
? minCapacity : SAFE_BOUND;
}
到这里,已经可以抛出结论了
在进行插入之后,字符串的总长度会决定它是否进行扩容
- 在长度小于16时,默认为
Capacity
- 在当长度大于16时,会进行一次扩容,新的长度为 16<<1+2=34
- 当新长度仍然不足大于34时,
newCapacity = minCapacity
,直接将数组长度赋值为字符串的长度 - 当新长度小于0,设定新长度为
MAX_ARRAY_SIZE
,或者大于Integer-8
时,抛出OOM