劳请各位大侠指教:
- String 是内容不可变的字符串,它的底层用的是final修饰的不可变 字符数组,而 其他2个是可变的,底层用的可变数组
- 在拼接字符串的时候String每次都生成一个新的对象,StringBuffer在原对象上进行拼接并且是线程安全的,StringBuilder在原对象上进行拼接但是线程不安全。
1、看下源码:
String源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
.....
}
在String 内部 其实是用的 final修饰的 字符数组 ,而 final修饰的变量有如下特性 :
- 必须赋值,不赋值则编译报错。
public class StringTest { private final String str; // 在类里面没有赋值 则这个地方报错 }
- 赋值之后就不可变,就是说除了第一次赋值 ,以后的任何赋值方法都会报错。
public class StringTest { private final String str = "123"; @Test public void test1(){ this.str = "234"; // 这里会报错 } }
- 要么在定义的时候赋值,要么在构造函数中赋值 若多个构造函数则每个构造函数都要赋值。
public class StringTest {
private final String str;
public StringTest(){
this.str = "";
}
public StringTest(String str2){
this.str = str2;
}
}
由此可见 Sting在每次发生变更的时候都是返回一个新的String对象。
2、那么为什么说StringBuffer 是线程安全的,而 StringBuilder是线程不安全的呢 ?
首先StringBuffer 和 StringBuilder 都是 都继承了AbstractStringBuilder ,最后值都存在这个value里面,而且他没有用final修饰 。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
......
}
那么在拼接字符串的时候 ,StringBuffer 使用这么用的
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
由源码可以看到 append方法用synchronized 修饰,所以他是线程安全的。
而StringBuilder 是这么用的
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
so : 由此可见。