String StringBuffer Stringbuilder的区别
1. 可变性
String
是不可变的(后面会详细分析原因)。
StringBuilder
与 StringBuffer
都继承自 AbstractStringBuilder
类,在 AbstractStringBuilder
中也是使用字符数组保存字符串,不过没有使用 final
和 private
关键字修饰,最关键的是这个 AbstractStringBuilder
类还提供了很多修改字符串的方法比如 append
方法
2. 线程安全性
String
中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder
是 StringBuilder
与 StringBuffer
的公共父类,定义了一些字符串的基本操作,如 expandCapacity
、append
、insert
、indexOf
等公共方法。StringBuffer
对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder
并没有对方法进行加同步锁,所以是非线程安全的。
3.性能
每次对 String
类型进行改变的时候,都会生成一个新的 String
对象,然后将指针指向新的 String
对象。StringBuffer
每次都会对 StringBuffer
对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder
相比使用 StringBuffer
仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
执行速度由快到慢:StringBuilder > StringBuffer > String
4. String为什么不可变
注意:String
类中使用 final
关键字修饰,所以String不可变,并不是String不可变的真正原因!
我们知道被 final
关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final
关键字修饰的数组保存字符串并不是 String
不可变的根本原因,因为这个数组保存的字符串是可变的(final
修饰引用类型变量的情况)。
String
真正不可变有下面几点原因:
- 保存字符串的数组被
final
修饰且为私有的,并且String
类没有提供/暴露修改这个字符串的方法。 String
类被final
修饰导致其不能被继承,进而避免了子类破坏String
不可变。
参考文献:
不可变有什么好处
我们可以看这段代码
public class Test01 {
public static void main(String[] args) {
String s1 = new String("aaa");
String s2 = Test01.appendStr(s1);
System.out.println(s1);
System.out.println(s2);
StringBuffer sb1 = new StringBuffer("aaa");
StringBuffer sb2 = Test01.appendStringBuffer(sb1);
System.out.println(sb1);
System.out.println(sb2);
StringBuilder sb3 = new StringBuilder("aaa");
StringBuilder sb4 = Test01.appendStringBuilder(sb3);
System.out.println(sb3);
System.out.println(sb4);
}
public static String appendStr(String s){
s+="bbb";
return s;
}
public static StringBuffer appendStringBuffer(StringBuffer stringBuffer){
return stringBuffer.append("bbb");
}
public static StringBuilder appendStringBuilder(StringBuilder stringBuilder){
return stringBuilder.append("bbb");
}
}
输出:
aaa
aaabbb
aaabbb
aaabbb
aaabbb
aaabbb
如果程序员不小心像上面例子里,直接在传进来的参数上加”bbb”,因为Java对象参数传的是引用,所以可变的的StringBuffer参数就被改变了。可以看到变量sb在Test.appendSb(sb)操作之后,就变成了”aaabbb”。有的时候这可能不是程序员的本意。所以String不可变的安全性就体现在这里。