文章目录
String、StringBuffer、StringBuilder区别详解(面试常问)
我们主要从三个方面来分析
可变性
String
我们深入查看String类的源码发现,String类是一个final类。同时发现在String类里面,使用的字符数组char[] value来保存字符串的,同时该数组也是被final所修饰的。同时该类的其他字段都是私有的且没有向外界提供任何的Set和Get去修改它,所以在String类的是无法修改String的,也就是说一旦被初始化就无法改变的,并且在类的外部无法访问这些成员。所以可以认为String类是不可变的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
/**
* Class String is special cased within the Serialization Stream Protocol.
*
* A String instance is written into an ObjectOutputStream according to
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence. Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.value = "".value;
}
下面我给大家说一下容易误导大家String可变的方法,同样进入源码层面分析。
比如常见的字符串使用“+”进行拼接,其实是+的重载操作符。其实使用"+"进行拼接之后返回的是一个新的对象,指向的是一个新的内存地址,而拼接前的字符串仍然在内存中,所以不能算作真正意义上的修改。另外如substring、replace等方法,基本都是以如下形式进行返回的,即都在内存中新建了一个字符串对象,这也是为什么这些方法都存在返回值的原因。
return new String(buf,true)
StringBuffer
StringBuffer是可变的
查看该类的源码,发现该类继承自AbstactStringBuilder,由字符数组保存,该数组没有被final修饰,同时还想外界提供一些方法去修改该数组,所以该类是可变的
StringBuilder
StringBuilder是可变的
和StringBuffer类似,该类同样继承自AbstractStringBuffer类。该类同样可变。
线程安全性
String
String线程安全
因为String类是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程所共享。
StringBuffer
StringBuffer线程安全
查看StringBuffer的源码发现,其几乎所以方法都被加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
StringBuilder
StringBuilder是线程不安全
查看StringBuilder的源码发现,其方法没有加同步锁,所以是非线程安全的
性能/执行效率
在性能执行效率方面,StringBuilder最高,StringBuffer次之,String最差。每次对String类型进行改变是,都会生成一个新的对象,然后将指针指向新的对象。而StringBuffer其实每次都是对对象本身进行操作,而不是生成新的对象改变引用。想通过情况下StringBuilder回比StringBuffer仅获得10%-15%左右的性能提升,但却要冒着多线程不安全的风险。
对于三者的使用总结
- 如果要操作的数据少的话,可以用String
- 单线程下操作大量数据,优先使用StringBuiler
- 多线程下操作大量数据,优先使用StringBuffer