String
String类的部分源代码:
public final class String {
private final char value[];
public String() {
this.value = new char[0];
}
public String(String original) {
/*把字符串分割成字符数组并赋值给value[]*/
}
}
可以看出:
(1)String被final修饰,不可继承。
(2)String中的字符数组value[]被final修饰,且只能被赋值一次,这是String为不可变对象的原因。每次对String句柄进行改变的时候,都会生成一个新的String对象,并将指针指向新的String对象。
StringBuilder与StringBuffer
StringBuilder与StringBuffer类的部分源代码:
public final class StringBuilder
extends AbstractStringBuilder {
char[] value;//继承于父类AbstractStringBuilder<span style="white-space:pre"> </span>
public StringBuilder() {
super(16);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
}
public final class StringBuffer
extends AbstractStringBuilder {
char[] value;//继承于父类AbstractStringBuilder
public StringBuffer() {
super(16);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
}
可以看出:
(1)StringBuilder与StringBuffer共同继承于父类AbstractStringBuilder。
(2)父类中的value[]并没有被final修饰,是一个很普通的数组,这就为后来的扩展提供了保障,此即StringBuilder和StringBuffer为可变对象的原因。可以通过append()方法将新字符串追加至value[]末尾。
(3)构造方法中将16作为字符数组的初始容量,当容量不足时,父类方法expandCapacity()会对字符数组进行扩容,为其指定新的长度并将旧字符数组中的数据copyOf到新字符数组中。
(4)StringBuffer类中,对字符串进行操作的主要方法都加了synchronized修饰符,而StringBuilder没有,故StringBuffer是线程安全的。
总结
- 如果要操作少量的数据,用String即可;单线程环境下操作字符串内容,用StringBuilder;多线程环境下操作字符串内容,用StringBuffer。
- StringBuffer因为对每个操作字符串的方法加锁,故实际性能比StringBuilder低。
- 为了获得更好的性能,在构造StringBuilder或者StringBuffer时应尽可能指定它们的容量。