StringBuilder
StringBuilder的构造器,无论是默认的无参构造器,或是指定容量的,或是指定字符串的,最终都是继承自AbstractStringBuilder的构造方法。
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
主要看一下append()方法
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
//再定位到AbstractStringBuilder的append方法
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
//扩容方法
void expandCapacity(int minimumCapacity) {
//2*len+2
int newCapacity = value.length * 2 + 2;
//如果2*len+2不够,则指定append后的长度为capacity
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
//溢出
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
//看下String的getChars方法
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);
}
//这里调用的是JVM实现的数组拷贝
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
toString
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
StringBuffer
StringBuffer多了一个字段toStringCache ,它表示上一次使用toString返回的字符串值的缓存。 每当StringBuffer被修改时清除。
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
StringBuffer的构造器同样继承于AbstractStringBuilder的构造方法
看一下StringBuffer的append方法
//注意这个方法是加了synchronized的
public synchronized StringBuffer append(String str) {
//修改时将toStringCache清空
toStringCache = null;
super.append(str);
return this;
}
//同样调用的是AbstractStringBuilder的append方法
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
String
看一下String的equals方法。由于StringBuilder和StringBuffer都没有重写equals方法,所以它们的equals方法之比较两个对象是否是同一个,不比较里面的具体值。
public boolean equals(Object anObject) {
//如果是同一个字符串对象,则为真
if (this == anObject) {
return true;
}
//如果不是同一个字符串对象,则比较字符串中的各个字符
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
//原字符串的字符数组
char v1[] = value;
//待比较字符串的字符数组
char v2[] = anotherString.value;
int i = 0;
//从第一个字符开始比较,遇到不同的字符则返回false
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s1.equals(s3));//true
记住 == 比较的是地址 String的equals()不仅比较地址,也比较字符串中的内容。
综合,效率方面 StringBuilder>StringBuffer>String。原因是String是常量,不可变的,每次修改都需要创建新的String对象;而StringBuilder和StringBuffer都是变量。又由于StringBuffer加了synchronized锁,需要申请获取锁以及释放锁,所以比StringBuilder慢。
StringBuffer是线程安全的,StringBuilder不是。