要说Java中什么哪个类用的最频繁,要数String类了。所以说,关于String 、StringBuffer、StringBuilder 是有必要详细研究一下的。
那么这三者之间有什么区别,如何根据场景来选择使用,本文将基于三者的源码、性能、以及面试常问点来进行分析。
String 类
我们先看看String的源码,看看Sting到底是个什么样的类
public final class String
implements java.io.Serializable, Comparable, 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* * Object Serialization Specification, Section 6.2, "Stream Elements"*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
可见,String类实现了CharSequence 接口,也就是说 String 是 CharSequence 类型。而且它是被final修饰的类,且底层的字符数组也是被final修饰的,这就意味着一旦String被定义之后就是固定的,不可改变的。
今天之所以要引入这个话题,是因为在做字符串拼接时的效率问题进行分析,我们在做简单的字符串拼接时,底层原理其实是创建新对象和回收旧对象的过程,这其中牵扯到了GC(垃圾回收机制),举个例子就明白了
String s1 = "abc" ;//1 s1 = s1 + "d" ;//2 System.out.println(s1);//3
可以看出,首先定义一个字符串s1,赋值为"abc",在执行第二行代码时,其实就是在原有s1的基础上拼接一个新的字符串"d",然后形成新的s1打印输出。
这个过程中,GC会回收旧的s1对象,同时创建新的对象(s1),但是这样的拼接过程在涉及到大量的字符串拼接时,就显得捉襟见肘了。
所以要想办法优化一下字符拼接,所以就出现了StringBuffer以及StringBuiler。
StringBuffer 类
StringBuffer 类继承自类AbstractStringBuilder,AbstractStringBuilder 类封装了大量基础方法,包括数组扩容机制、拼接方法等。
StringBuffer 初始化时默认长度大小为 16,它的扩容方式是在旧的数据上乘以 2 并加 2 进行扩容,StringBuffer实现字符串拼接用到了append 方法,这里摘抄一下append 方法的源码
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
可以看到,Stringbuffer底层的append方法是被synchronized标识的,因此StringBuffer是线程安全的,所以总的来说,StringBuffer提高了线程安全性,但是牺牲了效率。
StringBuiler 类
StringBuilder 与 StringBuffer 是类似的,都是继承自AbstractStringBuilder,所以很多功能都相似,但是不同的是它们的append方法不同,StringBuilder的append方法,不是由synchronized标识,所以相对于StringBuffer来说,StringBuilder不是线程安全的。
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
所以说,StringBuffer和StringBuilder相对于String来说,极大地提高了字符串拼接的效率,在使用时选择怎样选择呢?
一般的话,对于字符串拼接较少、字符串变化较小的的情况,可以选择String
当字符串连接操作比较频繁,且要求线程安全(多线程环境下操作)时,选择StringBuffer
而StringBuiler 适用于字符串连接操作比较频繁,且是单线程的情况。