Java提供了StringBuffer和String类,String通常是用来操作不用改动的常字符串。String对象一般是只可读不变的。而StringBuffer类通常是用来表示可以改变的字符串。
两个类的最主要的区别在于StringBuffer在进行字符串连接操作时候要比String效率更高,执行速度较快。在操作String的代码中,字符串的连接通常是如下的代码:
String str = new String ("Stanford ");
str += "Lost!!";
如果你用StringBuffer来处理同样字符串连接操作,你会看到的代码一般如下:
StringBuffer str = new StringBuffer ("Stanford ");
str.append("Lost!!");
程序员通常假设第一段代码比第二段来着更为高效,因为第二段代码使用了append方法来进行字符串的连接,这样要比第一段代码来的更为复杂,第一段代码只是运用了“+”运算符来进行连接操作。
+运算符看上去很清晰简单,但是生成的bytecode却揭示了不同的结果。StringBuffer在进行字符串连接操作时候要比String效率更高。让我们来近距离的观察一下两者bytecode的区别:
String的bytecode如下:
0 new #7 <Class java.lang.String>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #12 <Method java.lang.String(java.lang.String)>
9 astore_1
10 new #8 <Class java.lang.StringBuffer>
13 dup
14 aload_1
15 invokestatic #23 <Method java.lang.String valueOf(java.lang.Object)>
18 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
21 ldc #1 <String "Lost!!">
23 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
26 invokevirtual #22 <Method java.lang.String toString()>
29 astore_1
0到9行的bytecode是执行第一行代码的,即:
String str = new String("Stanford ");
然后10到29行执行的是第二行代码,即:
str += "Lost!!";
有意思的是,生成的bytecode中揭示了连接字符串的过程中创建了一个StringBuffer对象,然后还触发了append方法:这个临时的StringBuffer类在第10行被创建,而后在23行append方法被调用。因为String类是不能改动的,所以各StringBuffer类必须被创建从而执行连接操作。
在连接操作通过StringBuffer类完成后,这个对象必须被转换成String类。这个类型转换工作是通过调用toString()方法完成的(26行)。这个方法通过临时的StringBuffer创建了一个新的String对象。这个从String转到StringBuffer,再从StringBuffer转到String的过程是非常耗费资源的。
总结一下,这两行代码(String类操作)导致了需要创建3个对象。
1. 一个String对象位于0
2. 一个StringBuffer对象位于10
3. 一个String对象位于26
现在让我们来看一下StringBuffer进行字符串连接所产生的bytecode:
0 new #8 <Class java.lang.StringBuffer>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
9 astore_1
10 aload_1
11 ldc #1 <String "Lost!!">
13 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
16 pop
0到9行是执行第一行代码:
StringBuffer str = new StringBuffer("Stanford ");
10到16行是执行字符串连接的:
str.append("Lost!!");
值得注意的是,就如同第一个例子一样,这次的代码调用了StringBuffer的append方法。不同在于,已经没有必要创建一个临时的StringBuffer类再把它转换成String对象了。这次的代码只创建了一个对象就是StringBuffer在位置0。
得出的结论是,StringBuffer连接要比String执行连接快出很多。显然StringBuffer应该尽可能用于这种类型的操作。如果需要String类的一些特殊功能,可以考虑先将StringBuffer用于字符串操作,然后执行一次类型转换,转成String对象。
英语原文:http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html