0
点赞
收藏
分享

微信扫一扫

StringBuffer源码探究

小云晓云 2022-05-20 阅读 114

StringBuffer

StringBuffer 框架图:

StringBuffer源码探究_ide
特点:

  • 增删改查使用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):

@Override
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)方法

@Override
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)方法

@Override
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)方法

@Override
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}

获取指定字符。

举报

相关推荐

0 条评论