Java中用于操作字符串的类有三种,分别是String、StringBuffer和StringBuilder类。下面对这几个类介绍一下:
1、String类
String类比较常用,String对象是不可变的,为什么不可变呢?看一下JDK中的String类源码就能理解了,如下为部分源码:
/** String 类中通过value数组来存储字符串,在这可以看到,此数组是通过final修饰的,所以String一旦创建,就不能再改了 */
/** The value is used for character storage. */
private final char value[];
然后说一下,String频繁操作字符串的效率,代码如下:
String str = "aaa"; //line 1
str = str + "bbb"; //line 2
以上2行代码的内存变化如下:
从上面我们可以看到,执行第1行代码将aaa赋值给str,此时会在堆内存中分配一个空间用于存储aaa(此处暂不考虑字符串池),当执行第2行代码时,由于上面提的String是不可变的,所以此时会分配一块临时空间用于存储bbb,并且会再分配一块内存来存储str+"bbb"的值,此时str指向这块新内存,存储"aaa"和"bbb"的内存块就属于待垃圾回收器回收的内存。
通过以上过程我们可以发现,如果频繁的对字符串进行如上的操作,JVM就会频繁的创建和回收内存,这样效率是比较低的。
2、StringBuffer类
StringBuffer类的特点主要有2个,一是字符串对象可变,二是线程安全,解析如下:
/* 这是StringBuffer类中用于存储字符串的数组源码,从下面我们可以看到,数组并没有被final修饰,
所以StringBuffer的对象是可变的(即JVM没有像String类那样频繁的对内存操作),
至于transient修饰词,有兴趣的可以自己查一下,这个是StringBuilder类没有的。 */
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
/** 这是StringBuffer源码中的其中一个append方法,StringBuffer通过什么来确保线程安全呢?
就是通过synchronized关键字,StringBuffer的其他方法都有synchronized关键字来修饰 */
public synchronized StringBuffer append(StringBuffer sb) {
toStringCache = null;
super.append(sb);
return this;
}
3、StringBuilder类
StringBuilder类是在JDK1.5中才引入的,之前版本是没有的,它的特点主要有2个,一是字符串对象可变,而是线程不安全,解析如下:
/** 以下这行代码是在AbstractStringBuilder类中的,由于StringBuilder继承了AbstractStringBuilder类,
所以此子类没有重新定义存储字符串的数组(StringBuffer也继承了AbstractStringBuilder类,但它有自己存储字符串的数组),
由于数组没有被final修饰,所以它的字符串对象是可变的 */
/**
* The value is used for character storage.
*/
char[] value;
/** 从StringBuilder中的append方法可以看出,它没有被synchronized关键字修饰,所以它不是线程安全的 */
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
总结:
String:适合操作少量的字符串对象间的操作。
StringBuffer:适合操作多线程环境下的字符串对象间的操作,由于是线程安全的,所以相比较StringBuilder更安全,但效率没有StringBuilder高。
StringBuilder:适合单线程环境下的字符串对象间的操作。