要知道三者之间的区别,就先看看其中的一些方法:
首先是String:
/** The value is used for character storage. */
private final char value[];
String里面维护了一个char类型的字符数组,并且使用了final关键字进行修饰,所以String对象是不可变的
再来看下StringBuilder:
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
......
StringBuilder继承了AbstractStringBuilder,它的所有构造方法都是来自于AbstractStringBuilder,然后看下AbstractStringBuilder这个类:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;//没有用final修饰
int count;
AbstractStringBuilder() {
}
/**
* 创建指定长度的char数组
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
......
从上面的代码可以看出,char[]value 但是没有用 final 关键字修饰,所以StringBuilder对象都是可变的
同理,查看StringBuffer的时候,它的构造方法也和StringBuilder一样,说明StringBuffer是可变的对象,但是它的其它方法是用synchronized 关键字进行修饰的,也就是说,StringBuffer使用了加上同步锁的机制来保证线程安全,StringBuilder的方法里面没有这个关键字,所以StringBuilder不能用于多线程的环境下.
......
public synchronized StringBuffer append(StringBuffer sb) {
toStringCache = null;
super.append(sb);
return this;
}
/**
* @since 1.8
*/
@Override
synchronized StringBuffer append(AbstractStringBuilder asb) {
toStringCache = null;
super.append(asb);
return this;
}
......
现在从以下3个方面总结下String,StringBuilder和StringBuffer:
- 可变性:
String 对象是不可变的,StringBuilder和StringBuffer是可变的对象,因为String 对象使用 final 关键字修饰字符数组来保存字符串,而StringBuilder和StringBuffer没有final关键字. - 线程安全性
String 对象是不可变的,可以理解为常量,毫无疑问,线程安全;
StringBuffer是可变对象,但是方法加上了synchronized 关键字保证了同步,所以线程安全;
StringBuilder线程不安全; - 性能
(通常情况下):StringBuilder > StringBuffer > String
因为String 不可变,所以每次对 String 类型进行改变的时候,都会在堆内存生成一个新的 String 对象,然后将指针指向新的 String 对象,旧的String 对象被JVM的垃圾回收机制(GC)回收掉。StringBuffer 和StringBuilder都是对对象本身进行操作,每次append()后都是返回this(也就是本类对象),由于StringBuffer使用了java的同步锁机制,所以它的操作比StringBuilder要慢一点.
总结:
- 操作少量的数据: 适用String;
- 单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder;
- 多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer.