1.继承体系
StringBuilder类:
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
StringBuffer类
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
StringBuilder 和StringBuffer都继承自AbstractStringBuilder这个抽象类
2.构造方法
StringBuffer类(共四个)
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
StringBuilder类的构造方法和StringBuffer的构造方法个数,参数和方法体完全一样
父类构造方法:共两个
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
AbstractStringBuilder() {
}
父类关键成员:
char[] value; //底层用字符数组实现
int count; //记录当前数组中存放的有效数据长度
测试:
public static void main(String[] args) {
StringBuilder sb=new StringBuilder();
StringBuilder sb2=new StringBuilder("hello");
StringBuilder sb3=new StringBuilder(2);
System.out.println(sb.length()); // 0
System.out.println(sb.capacity()); // 16
System.out.println(sb2.length()); // 5
System.out.println(sb2.capacity()); // 5+16=21
System.out.println(sb3.length()); // 0
System.out.println(sb3.capacity()); // 2
}
从源码可知:使用StringBuilder无参构造方法创建一个对象,会使用父类的有参构造方法,默认开辟一个长度为16的字符数组。
如果使用字符串的有参构造,则会在当前字符串长度的基础上+16
也可以使用另一个有参构造直接指定底层数组的长度
length和capacity方法都是使用的父类中的方法:
public int length() {
return count;
}
public int capacity() {
return value.length;
}
3.常用方法:append(String s): 作用是拼接字符串并返回当前StringBuilder对象
public StringBuilder append(String str) {
super.append(str);
return this;
}
//父类中的append方法
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); //拼接后的字符串长度作为参数,里面会调用复制数组的方法。
str.getChars(0, len, value, count); //复制str到新数组的后半部分
count += len;
return this;
}
//判断是否需要扩容,不需要直接退出
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) { // 满足说明需要扩容
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
/*
copyOf方法的作用是将value数组复制到指定长度也就是newCapacity(minimumCapacity)的返回
值的新数组中
*/
}
//该方法的作用是返回数组需要扩容到的长度
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2; //相当于value.length*2+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity; //如果扩容后还是小于需要的最小长度,则newCapacity直接等于最小的长度。
}
// 上面如果value.length值很大,则newCapacity有可能越界,越界则为负数或0
//如果越界或者newCapacity大于了MAX_ARRAY_SIZE,则返回hugeCapacity(minCapacity)
//否则返回newCapacity
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;
}
总结:append(String s) 方法,会首先判断是否需要扩容,不需要则直接将参数字符串复制到源字符数组后面,如果需要扩容,则使用类的扩容机制也就是 newCapacity()方法返回需要扩容到的容量,ensureCapacityInternal方法会将源数组复制到扩容好的新数组中,然后在调用字符串的getChars方法,将需要拼接的字符串复制到新数组的后面,完成拼接,返回对象本身。
StringBuffer和StringBuilder一样,都是调用的同一个父类中的append方法,所以扩容的方式相同。
append方法有很多重载,几乎可以拼接所有其他类型,StringBuffer和StringBuilder可以相互拼接。
4.StringBuffer和StringBuilder的不同点
4.1 StringBuilder中几乎所有的public方法都是直接调用的父类中对应的方法来实现的,而StringBuffer因为被设计成线程安全的类,所以大部分方法都是重写了父类中的对应方法,并且加上关键字synchronized,但是方法体的实现还是调用父类中的方法。
如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。
4.2 toString实现不同
//StringBuffer中:
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
//StringBuilder中:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}