周三代码review的时候,提出了这个问题,自己感觉还是有点凌乱,所以重新梳理下。
从网上找的图,觉得特别清晰。
1,可变和不可变
String类中使用字符串数组来保存字符串,因为有final关键字修饰 ,所以string 对象是不可以改变的。
private final char value[];
StringBuilder 和StringBuffer都继承了AbstractStringBuilder类,在AbsractStringBuilder中也是使用字符串数组来保存字符串,但是没有final关键字,,所以是可以改变的。
char[] value;
2,线程安全和不安全String中的对象是不可以改变的,可以理解为常量,所以线程安全。
StringBuffer对方法加了同步锁和对调用的方法加了同步锁,所以是线程安全的。
public synchronized StringBuffer reverse() {
super.reverse();
return this;
}
public int indexOf(String str) {
return indexOf(str, 0); //存在 public synchronized int indexOf(String str, int fromIndex) 方法
}
StringBuilder并没有对方法进行添加同步锁,所以线程是非安全的。
3,效率高否
三者在执行效率方法的比较:StringBuilder>StringBuffer>String
String创建的是不可改变的对象,正是由于这种机制,每当String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉了。所以这样效率会变低。所以经常改变的内容尽量不要使用String。每次生成对象都会对系统性能产生影响。
而StringBuilder和StringBuffer是可变的对象,是字符串变量,每次我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像、string一样创建一些额外的对象进行操作了。当然速度就比较快了。
应用场景总结:
(1)如果要操作少量的数据用String
(2)单线程操作字符串缓冲区下操作大量数据用StringBuilder.
(3)多线程操作字符串缓冲区下操作大量数据用StringBuffer.
3,StringBuilder和StringBuffer的共同点
两者继承了公共父类:AbstractStringBuilder这个抽象类。都会调用AbstractStringBuilder的公共方法,例如super.append().只是StringBuffer方法会在调用的时候,加上synchronized关键字,进行同步。
参考资料:
Java String、StringBuilder、StringBuffer实例
StringBuilder、StringBuffer、String对比 作者讲解很深入,非常推荐。