1. 描述:
-
StringBuilder
和StringBuffer
都是AbstractStringBuilder
的子类,String
的可变方式,String
不可变操作只能new一个新对象,效率不高。
- 字符串类都使用字符数组保存,
String
数组的长度是固定的,这两个类可变,所以会有数组长度变化的问题。
-
StringBuilder
线程不安全,StringBuffer
线程安全但速度相比较慢,但拼接肯定都比String
快。
-
StringBuilder、StringBuffer
,主要就是append()
和insert()
的各种重载方法对value[]
进行操作。
-
核心字段(字段在父类AbstractStringBuilder中):
-
char[] value
:和String一样,StringBuilder、StringBuffer也是字符数组,但可变。
-
int count
:存储value[]
已有元素个数。数组总长直接调用value.length
。
-
private transient char[] toStringCache;
:StringBuilder独有的value[]缓存,后面会具体说。
2. 构造函数(StringBuilder)
//以入参”AAAA“为例
public StringBuilder(String str) {
//初始数组长度就是4 + 16
super(str.length() + 16);
//调用AbstractStringBuilder的append(str),StringBuilder和StringBuffer的父类
append(str);
}
public AbstractStringBuilder append(String str) {
if (str == null)
//数组当前后添加{'n','u','l','l'}
return appendNull();
int len = str.length();
//扩容
ensureCapacityInternal(count + len);
//利用System.arraycopy()把str补到后面
str.getChars(0, len, value, count);
//记录已有元素个数
count += len;
return this;
}
//计算扩容长度,用Arrays.copyOf()设置value[]
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
//计算扩容后长度。minCapacity是期望长度
private int newCapacity(int minCapacity) {
// 2*minCapacity + 2
int newCapacity = (value.length << 1) + 2;
//如果还不够大直接等于minCapacity
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//边界判定最大不超过Integer.MAX_VALUE,return
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
- 可传入
String
、CharSequence
、初始化容量、无参四种,除传入容量其他方式都是默认字符串长度 + 16
- 扩容长度:原数组长度* 2 + 2,如果还是不够,直接扩容到传入的期待值minCapacity。
3. append()(StringBuilder)
- 构造函数中介绍了append(),append()有很多重载方法,传入int、double、boolean等,最终都是转成字符拼到了value[]后面,例如
"AAAA 1 1.11 false"
4. insert()(StringBuilder)
public AbstractStringBuilder insert(int offset, char c) {
ensureCapacityInternal(count + 1);
System.arraycopy(value, offset, value, offset + 1, count - offset);
value[offset] = c;
count += 1;
return this;
}
-
insert()
和append()
的区别就是insert()
可以指定下标插入字符串,两者源码上区别不大,都是利用System.arraycopy()做的数组拼接。
5. StringBuilder和StringBuffer
- 前面说到两者的区别就是线程安全,除了线程优化其他几乎没有区别:
- StringBuffer在方法上加synchronized保证线程安全。
- StringBuffer调用toString()时并发的优化:
//-- StringBuilder.java --
public String toString() {
return new String(value, 0, count);
}
//-- StringBuffer.java --
private transient char[] toStringCache;
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
- StringBuilder的toString()创建了一个新的value[],因为不适用于并发,所以没有并发优化。
- StringBuffer的toString()把value[]提前新建并存在了toStringCache里,任何修改时都会更新toStringCache,并发量大时不会每次调用都new一个新的String。
网友评论