一、String是字符串常量,对象不可变。StringBuffer与 StringBuilder是字符串变量,对象可变。
先来看String的字符串拼接代码:
String A = "aaa";
System.out.println(A);
A = "bbb";
System.out.println(A);
//输出结果:
//aaa
//bbb
看到上面的结果就奇怪了,不是说String不可变吗,怎么从"aaa"变成"bbb"了?
其实你看到的只是表象,其实第一个"aaa"和"bbb"已经不是同一个对象,"bbb"对象是重新生成的新对象,只不过之前引用A是指向对象"aaa"的,后来指向了对象"bbb",而"aaa"由于没有被引用,被JVM回收了。
所以看上去像是一个对象被修改了,而事实上是完全不同的两个对象。
再来看StringBuffer和StringBuilder的拼接代码:
StringBuffer str = new StringBuffer();
str.append("aaa");
str.append("bbb");
System.out.println(str.toString());
//输出结果:
//aaabbb
StringBuilder str = new StringBuilder();
str.append("aaa");
str.append("bbb");
System.out.println(str.toString());
//输出结果:
//aaabbb
可以看出,StringBuffer和StringBuilder都是使用append方法来进行拼接,他们的操作都是在一个对象上完成的。
二、StringBuffer是线程安全的,StringBuilder是线程不安全的。
下面这是StringBuffer源码片段,StringBuffer在几乎所有的方法上都加了synchronized加锁,这样就能保证多线程并发操作下的线程安全。
//StringBuffer源码片段
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
再来看StringBuilder的源码,同样的append操作,StringBuilder并没有加锁,所以StringBuilder是非线程安全的。
//StringBuildera源码片段
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
三、执行速度不同。StringBuilder > StringBuffer > String
1、String 每次进行修改操作都会新建对象,对于JVM是一种负担,耗时耗力,特别在大量拼接的情况下,尤为明显。所以三者中String最慢。
2、StringBuffer为了能保证线程安全,在其每个方法都用synchronized加锁,加锁和释放锁本身就会消耗系统资源,所以论速度,StringBuffer不及StringBuilder。
3、StringBuilder操作不需要加锁,也不会产出多个对象拼接,所以StringBuilder速度是最快的。
四、如何选用
1、String操作简单,代码量小,适合在简单字符串操作中使用。
2、StringBuffer适合在多线程情况下使用,保证线程安全。
3、在单线程情况下,对于复杂的字符串操作,StringBuiler是很不错的选择。