String,StringBuffer,StringBuilder大体区别
String是final修饰的,不可变的,每次操作都会产生新的String对象
StringBuffer和StringBuilder都是在原对象上操作
StringBuffer是线程安全的,StringBuilder线程不安全的
StringBuffer方法都是synchronized修饰的
性能:StringBuilder>StringBuffer>String
应用场景:经常需要改变字符串内容时尽量不要使用String,优先使用StringBuffer,多线程使用共享变量时使用StringBuffer
三者源码分析
String
1.String的value[]是final定义的,是不可变的,所以每次操作都会产生新的String对象
private final char value[];
2.不继承抽象类AbstractStringBuilder
StringBuilder和StringBuffer
两者底层代码相同点:
这两个类都是继承抽象类AbstractStringBuilder,初始容量池为16
public StringBuilder() {
super(16);
}
public StringBuffer() {
super(16);
}
那我们看AbstractStringBuilder源码
value没有被final修饰,说明可变
char[] value;
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
AbstractStringBuilder的append扩容机制:
每次append都会调用ensureCapacityInternal(int minimumCapacity)方法
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public AbstractStringBuilder append(String str或者StringBuffer sb或者AbstractStringBuilder asb) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
ensureCapacityInternal(int minimumCapacity)方法中又调用了newCapacity(minimumCapacity)方法
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
int newCapacity = (value.length << 1) + 2;内存扩大两倍+2;如果太大就进行hugeCapacity(minCapacity)方法进行溢出检测
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;
}
hugeCapacity(int minCapacity)检测溢出
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
总体下来和ArrayList()的扩容机制差不多
两者底层代码不同点:
StringBuffer:
-
private transient char[] toStringCache;这一行代码是缓存,缓存最后一次toString的内容,如果我们没有对StringBuffer进行修改的话,我们再次toString的话不需要arraycopy的操作,这样可以平衡StringBuffer的性能
-
几乎每个方法都加上了synchronized线程锁,保证线程安全
-
每次对StringBuffer修改都会toStringCache=null,也就是清空toStringCache
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
StringBuilder:
-
没有synchronized,性能比StringBuffer要好
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}