StringBuffer
StringBuffer 框架图:
特点:
- 增删改查使用synchronized修饰,保证线程安全,同时不可避免效率较低。
- StringBuffer是一个可变序列。
创建StringBuffer对象:
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
// 默认 new StringBuffer()
public StringBuffer() {
super(16);
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
在默认情况下,value数组的大小为16。
append(String str)方法
append(String str):
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
方法被synchronized关键字修饰, 这也是StringBuffer 线程安全的原因。
toStringCache:
private transient char[] toStringCache;
toString返回的最后一个值的缓存。每当修改StringBuffer时清除。
super.append(str):
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count); //参数1:从0索引开始 参数2:复制指定的长度 参数3:目标数组 参数4:从目标数组的指定索引位置粘贴
count += len;
return this;
}
通过ensureCapacityInternal(int minimumCapacity) 方法选择是否需要扩容。
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
count + len 计算出追加字符串之后的大小,使其于当前数组value的长度进行比较,如果小于则说明不需要扩容,反之调用newCapacity(int minCapacity)进行计算扩容后数组的大小,之后调用Arrays.copyOf(value, newCapacity(minimumCapacity)),进行扩容操作。(创建新的数组 大小为minimumCapacity,并复制value值)。
private static final int 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; //不够直接使用minCapacity
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
扩容机制大小当前数组的长度乘以2+2 即 value.length*2+2。之后判断扩容之后的大小是否足够,不足够则使用当前追加后数组的大小。MAX_ARRAY_SIZE - newCapacity < 0,判断数组是否过大,过大抛出OutOfMemoryError 内存溢出异常。
delete(int start,int end)方法
public synchronized StringBuffer delete(int start, int end) {
toStringCache = null;
super.delete(start, end);
return this;
}
该方法用于删除字符串,start 为开始,end为结尾(数组下标),例如:
StringBuffer a = new StringBuffer("ss1111");
a.delete(1,3);
// 结果
s111
通过父类AbstractStringBuilder delete(int start, int end)进行删除操作。
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start); // 数组下标越界异常
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len;
}
return this;
}
System.arraycopy(src,srcPos,dest,destPos,length)复制数组。
- src:源数组;
- srcPos:源数组要复制的起始位置;
- dest:目的数组;
- destPos:目的数组放置的起始位置;
- length:复制的长度.
例如:
数组1:int[] arr = { 1, 2, 3, 4, 5 };
数组2:int[] arr2 = { 5, 6,7, 8, 9 };
运行:System.arraycopy(arr, 1, arr2, 0, 3);
得到:
int[] arr2 = { 2, 3, 4, 8, 9 }
replace(int start, int end, String str)方法
public synchronized StringBuffer replace(int start, int end, String str) {
toStringCache = null;
super.replace(start, end, str);
return this;
}
用于修改字符串,例如:
StringBuffer a = new StringBuffer("ss1111");
a.replace(0,2,"2");
//结果
21111
调用父类replace(int start, int end, String str)方法。
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end");
if (end > count)
end = count;
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);
System.arraycopy(value, end, value, start + len, count - end); // value 空出待修改字符串的大小
str.getChars(value, start); // vaule目的数组,start,目的数组开始位置,将字符串复制到start之后
count = newCount;
return this;
}
计算修改后数组的大小newCount,判断数组是否需要扩容(扩容见append(String str))方法,调用System.arraycopy方法,空出待修改部分,调用str.getChars(value, start),将str复制到value空出的部分。
charAt(int index)方法
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
获取指定字符。