String是不可变类,也就是说String对象一旦被创建,其值将不能被改变,而StringBuffer是可变类,当对象被创建后仍然可以对其值进行修改。由于String是不可变类,因此适合在需要被共享的场合中使用,而当一个字符串需要经常被修改时,最好使用StringBuffer来实现。如果用String来保存一个经常被修改的字符串时,在字符串修改时会比StringBuffer多很多附加的条件,同时产生很多无用的对象,由于这些无用的对象会被垃圾回收器回收,因此会影响程序的性能,在规模小的项目里面这个影响很小,但是在一个规模大的项目里面,这会对程序的运行效率带来很大的影响。
String与StringBuffer的另外一个区别在于当实例化String时,可以利用构造函数String str = new String("hello");
的方式对其初始化,也可以用赋值String str = "hello";
的方式来初始化,而StringBuffer只能通过构造函数StringBuffer str = new StringBuffer("hello");
的方式来初始化。
String字符串修改实现的原理如下:当String类型来对字符串进行修改时,其实现方法是 首先创建一个StringBuilder,其次是调用StringBuilder的append()方法,最后调用StringBuilder的toString()方法将结果返回。
String s = "hello";
s += " world";
等价于:
StringBuilder sb = new StringBuilder(s);
s.append(" world");
由此可以看出,上述过程比使用StringBuilder多了一些附加的操作,同时也生成了一些临时的对象,从而导致程序的执行效率降低。
public class Test {
private static void testString(){
String s = "Hello";
String s1 = " world";
long start = System.currentTimeMillis();
for(int i = 0 ; i < 10000;i++){
s += s1;
}
long end = System.currentTimeMillis();
long runTime = end- start;
System.out.println("String:"+runTime);
}
private static void testStringBuilder(){
StringBuilder s = new StringBuilder("Hello");
String s1 = " world";
long start = System.currentTimeMillis();
for(int i = 0 ; i < 10000;i++){
s.append(s1);
}
long end = System.currentTimeMillis();
long runTime = end- start;
System.out.println("StringBuilder:"+runTime);
}
public static void main(String[] args) {
testString();
testStringBuilder();
}
}
显而易见,当一个字符串需要经常被修改时,使用StringBuilder比使用String好的多。
StringBuilder也可以用于被修改的字符串,它与StringBuffer类似,都是字符串缓冲区,但是StringBuilder不是线程安全的,如果只是在单线程中使用字符串缓冲区,那么StringBuilder的效率更高一些,因此在只有单线程访问时可以使用StringBuilder,当有多个线程访问时,最后使用线程安全的StringBuffer
在执行效率方面,StringBuilder最高、StringBuffer次之,String最低。一般而言,
- 如果要操作的数量比较小,应优先使用String类
- 如果实在单线程条件下操作大量数据,优先使用StringBuilder类。
- 如果是在多线程下操作大量数据,优先考虑StringBuffer类。