首先从执行效率上来说 String < StringBuffer < StringBuilder
有一种情况例外
一下情况 String a = “1”+”2” + “3” +”abc”; JVM会直接理解为 String a=”123abc”;
String a = "1"+"2" + "3" +"abc";
System.out.println(a);
StringBuffer b = new StringBuffer("1")
.append("2").append("3").append("abc");
System.out.println(b);
String 关键源码
private final char value[];//final类型char数组
java 中的String 实际是用final修饰的字符数组,在String 执行过程中
每个String 标志位意味着 一次new 对象的操作,必须去内存中(栈)申请新的地址空间用于存放这个新的对象
这里用 == 操作符 比较String 和StringBuffer 的对象引用是否相同
String a ="aaac";
String b = a + "bbb" ;
String c = a.replace("c","a");
//这里 a 和 b 是不同的对象引用
System.out.print(a == b);
System.out.println(a == c);
System.out.println("StringBuffer");
StringBuffer aa = new StringBuffer("aaa");
StringBuffer bb = aa.append("123");
StringBuffer cc = aa.replace(1,2,"c");
System.out.println(aa == bb);
System.out.println(aa == cc);
//这里 aa = bb = cc 同一对象引用
StringBuffer 关键源码:
/**
* @since JDK1.0.2
*/
@Override
public synchronized StringBuffer reverse() {
toStringCache = null;
super.reverse();
return this;
}
可以看到很多 StringBuffer的方法都被加上了 synchronized ,即是多个对当前StringBuffer类的 某个 对象的 这些方法访问的时候 只有一个访问将被执行,其他的访问将被阻塞等待,也就是说 StringBuffer不存组线程安全的问题。
关于锁的问题
详见这位博主的博客
StringBuilder 源码与StringBuffer 源码一样 , 只是 StringBuffer 在每个方法前加上了 synchronized 。
StringBuilder 安全性测试代码:
public class testStringBuilder {
public static void main(String arg[]){
StringBuffer sbf = new StringBuffer();
StringBuilder sbi = new StringBuilder();
//10个 线程
for(int i = 0;i<10 ;i++){
new Thread(new TestThread(sbf,sbi)).start();
}
}
}
class TestThread implements Runnable{
StringBuffer sbf ;
StringBuilder sbi;
TestThread(StringBuffer sbf,StringBuilder sbi){
this.sbf = sbf;
this.sbi = sbi;
}
@Override
public void run() {
for (int i=0;i <10;i++){
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
sbi.append("1");
sbf.append("1");
// sbi 会有遗失现象
System.out.println(sbi.length() + "/" + sbf.length());
}
}
}