StirngBuffer和StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
public StringBuilder() {
super(16);
}
}
---------------------------------------------------
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
public StringBuffer() {
super(16);
}
}
AbstractStringBuilder:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
//元素个数
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
public int length() {
return count;
}
public int capacity() {
return value.length;
}
}
StringBuffer和StringBuilder都是final修饰的最终类不允许被继承,
他们的append等大部分方法主要功能实现是直接利用super调用父类的方法来实现,他们继承的抽象父类:AbstractStringBuilder。
StringBuffer和StringBuilder都表示可变字符串,StringBuffer在方法上加 上synchronized来保证线程安全,效率不高,StringBuilder效率高,不保
证线程安全。从操作效率上来讲推荐使用StringBuilder,从多线程操作安全上来说推荐使用StringBuffer。
StringBuffer和StringBuilder字符串都已是以字符的方式存储在普通的字符数组中,String类的字符串是以字符的形式存储在final修饰的字符数
组中,所以StringBuffer和StringBuilder为可变字符串,可以改变字符数 组的长度,是保证不产生新对象的情况下改变字符串的长度;String是不
可变的字符串,底层的数组不允许重复的改值,但每次对于String变量的修改实质上是一个新的字符串对象引用重新赋值给这个String变量或在字
符串常量池中存在的引用赋值给这个String变量。
StringBuffer和StringBuilder追加字符串原理机制
一、默认无参构造创建对象
StringBuffer和StringBuilder的无参构造内都是调用父类指定容量的方法:super(16);
无参构造将存储字符数组的初始容量变为16:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
二、追加字符串
(debug)测试代码:
public static void main(String[] args) {
StringBuilder s1 = new StringBuilder();
s1.append("ABCDEFG");
s1.append("HIJKLMNOPQ");
StringBuffer s2 = new StringBuffer();
s2.append("ABCDEFG");
s2.append("HIJKLMNOPQ");
}
StringBuilder和StringBuffer对象的创建时,存储字符串的数组初始化为父抽象类定义的字符数组属性:value=new char[16];
append方法(append及以下方法都是AbstractStringBuilder抽象父类中的方法):
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
//检索存储字符串的容量,不够就会扩容
ensureCapacityInternal(count + len);
//调用字符串对象的getChars方法,将当前String对象添加到指定字符数组中
str.getChars(0, len, value, count);
//在成功添加后,count增加str长度大小
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// 当所需容量大于数组长度时扩容
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// 扩大的新容量:原来数组的长度的俩倍加2,原构造的默认容量为16,扩容后为34
int newCapacity = (value.length << 1) + 2;
//得到新容量后进一步判断容量是否够,如果不够就直接该为所需容量
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//如果扩容容量在0-MAX_ARRAY_SIZE范围内就直接返回这个容量
//如果判断所需的容量进一步操作,所需容量小于0异常,大于最大值就不再增加,直接改为最大值
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
容量检索操作完成之后继续执行后续方法
/**
* getChars是String类中的对象方法
* srcBegin:需要赋值当前字符串对象字符的开始索引
* srcEnd:需要赋值当前字符串对象字符的最后索引
* dst: 所需复制到的目标字符数组
* dstBegin: 复制到dst开始的位置
*/
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
结论:StringBuffer和StringBuilder是一个可变字符串,可变的原因:底层存储字符串的字符数组没有用final修饰,每次拼接字符串使用append方法,追加拼接字符串的实现原理为给存储的字符串数组添加字符元素或扩容后再添加。值得注意的是StringBuffer和StringBuilder的父类都是抽象父类AbstractStringBuilder,重写父类方法,StringBuffer将对存储字符串的字符数组的方法加了synchronized保证线程安全,而StringBuilder没有次操作,StringBuilder的效率比StringBuffer高,StringBuilder的多线程不安全。
注意:StringBuffer中一个由意思的属性:private transient char[] toStringCache;对于这个属性的解释是:toString返回的最后一个值的缓存,每当修改StringBuffer时清除。也就是说在StringBuffer的toString方法中,会产生一个新的字符数组,这个新的字符数组(由toStringCache缓存所创建)被toString方法拿去给创建的String对象内的字符数组所引用
源码:
//StringBuffer中的toString方法
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
//String内的构造方法,使用的默认访问权限(包访问权限)
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
对比StringBuilder的toString方法:
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}