我找到了 Reggie Hutcherso 比较性能 String 与 StringBuffer 的有趣答案
来源:http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html
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 方法进行连接的第二个示例比使用 + 运算符连接两个 String 对象的第一个示例成本更高。
+ 操作符看似无辜,但生成的代码却产生了一些意外。使用 StringBuffer 进行连接实际上可以生成比使用 String 快得多的代码。要发现为什么会这样,我们必须检查两个示例中生成的字节码。使用 String 的示例的字节码如下所示:
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 的字节码针对第一行代码执行,即:
String str = new String("Stanford ");
然后,执行位置 10 到 29 的字节码进行连接:
str += "Lost!!";
这里的事情变得有趣了。为连接生成的字节码创建一个 StringBuffer 对象,然后调用它的 append 方法:临时 StringBuffer 对象在位置 10 创建,它的 append 方法在位置 23 处调用。由于 String 类是不可变的,因此必须使用 StringBuffer串联。
对StringBuffer对象进行拼接后,必须将其转回String。这是通过在位置 26 调用 toString 方法来完成的。该方法从临时 StringBuffer 对象创建一个新的 String 对象。这个临时 StringBuffer 对象的创建及其随后转换回 String 对象的成本非常高。
综上所述,上面两行代码导致了三个对象的创建:
- 位置 0 的字符串对象
- 位置 10 的 StringBuffer 对象
- 位置 26 的字符串对象
现在,让我们看看使用 StringBuffer 为示例生成的字节码:
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 对象。此代码仅在位置 0 处创建一个对象,即 StringBuffer。
总之,StringBuffer 连接明显快于 String 连接。显然,StringBuffers 应该尽可能用于这种类型的操作。如果需要 String 类的功能,请考虑使用 StringBuffer 进行连接,然后执行一次到 String 的转换。