String、StringBuild、StringBuffer
String、StringBuild、StringBuffer在java中都是可以操作字符串的对象,让我们来看看它们之间的区别和联系。
从结构分析
从结构上来看,它们都是final类,并且都是用char数组来存储内容的,不过StringBuild、StringBuffer没有用final和private来修饰这个数组。
StringBuild、StringBuffer都是继承AbstractStringBuilder,但StringBuffer为了解决线程安全问题,在对应的方法加上了关键字。
从线程是否安全分析
从线程安全方面来讲,String是不可变的,所以是线程安全的,因为多个线程调用String的方法都会去产生一个新的String,不会改变最初的内容。(之前我总是认为String做拼接的时候,是线程不安全的,所以String是线程不安全的,其实他指的线程安全并不是这个意思,因为拼接已经不是原子操作了,它只是指Sring调String的方法不会发生线程安全问题。)
StringBuild是非线程安全的,StringBuild也是用char数组去存储的,它其中某些方法是直接去操作这个数组的,比如append方法所以在多线程情况下是不安全的。
StringBuffer是线程安全的,虽然StringBuffer和StringBuild方法和属性几乎一样、都是继承AbstractStringBuilder。但是StringBuffer的方法有synchronize修饰。
String和StringBuild
String对象用“+”去拼接时,其实是使用了StringBuild对象。`
public static void main(String[] args) {
String a="mihou";
String b="tao";
String c=a+b;
}
上面是测试代码和对应的字节码。我们可以看到字节码中,先初始化了两个String对象,然后再新建了一个StringBuild对象,再调用了StringBuild的append方法,将两个String对象拼接进去,然后返回StringBuild的toString。
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
StringBuild的toString是返回一个String对象。
String c=“mihou”+“tao”,这个语句是没有创建StringBuild对象的,因为前面我们讲了必须是一个String对象使用了“+”,而“mihou”+“tao”其实只在常量池里面创建了“mihoutao”这一个对象,如果说“mihou”或者“tao”是String对象的话,就会创建StringBuild。那怎么去验证没有创建“mihou”对象呢?这里有两种办法,一种是去看字节码。
这里我们可以看到只初始化了一个“mihoutao”。
还有一种办法是使用intern方法,jdk至少1.7。
public static void main(String[] args) {
String a="mihou"+"tao";
String b=new String("mi")+new String("hou");
System.out.println(b.intern()==b);
}
这里输出是true,刚好证明了常量池中没有”mihou”对象。
从效率分析
上面我们讲了String在拼接时底层使用了Stringbuild,所以在这种拼接的时候效率是一样的,不过在循环中拼接就会循环创建Stringbuild,这时效率就会低些。而用Stringbuild可以把对象创建在循环外,避免这种情况。
String中的方法,每次对产生新的对象,而Stringbuild是在原来的基础上修改,所以String的开销大些。
Stringbuild和StringBuffer的差别在于StringBuffer要加锁,释放锁。主要的开销大小区别就在这里,所以Stringbuild的效率高。
综上所述,Stringbuild的效率总体来说是高于String和StringBuffer。String和StringBuffer的效率就要具体分析了,主要是看锁消耗和频繁创建对象哪个开销大。