StringBuilder 是可变的,而 String 是不可变的。不可变意味着它不会改变,所以你关于它不同步的观点是没有意义的 - 没有可能要同步的变化。
简而言之,如果您不需要 StringBuilders 的额外功能(这在字符串中很常见),那么 String 的效率会更高。它还在 JVM 中具有 Java 中其他对象所没有的高度优化的特殊处理。
字符串特定优化的最显着示例,字符串池,它使字符串表现得像常量,因为同一个实例可以在整个应用程序中自动共享,从而节省内存和时间。对于其他对象,这不会自动实现,对于可变对象,通常甚至不需要。与定制池相比,字符串池已显示允许more objects with better performance。为了提高性能而只使用一个字符串实例的过程称为string interning。
由于您只使用一个实例,因此在比较时,您只需比较参考。对于每个 StringBuilder 实例,您需要评估对象的内容才能做到这一点。 Stringbuilder uses an Array as a backing object 并且必须遍历该 Array 以获取其内容,这相当昂贵。这假设您对字符串内容而不是对象实例感兴趣,String/StringBuilder/StringBuffer 几乎总是如此。
String 和 StringBuilder 内容的简单性能测试比较:
public class CompTest {
// fastest way to compare StringBuilder contents according to
// http://stackoverflow.com/questions/11007387/what-is-an-efficient-way-to-compare-stringbuilder-objects
static boolean contentEquals(StringBuilder sb1, StringBuilder sb2) {
if (sb1.length() != sb2.length()) return false;
for (int i = 0, len = sb1.length(); i < len; i++) {
if (sb1.charAt(i) != sb2.charAt(i)) return false;
}
return true;
}
public static void main(String args[]) {
StringBuilder fooSb = new StringBuilder("foo");
StringBuilder barSb = new StringBuilder("foo");
String foo = "foo";
String bar = "foo";
System.out.println(foo.equals(bar));
// returns true
System.out.println(fooSb.equals(barSb));
// returns false, so cannot be used to check contents
System.out.println(contentEquals(fooSb,barSb));
// returns true
long time;
time = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
if (foo.equals(bar)) continue;
}
System.out.println("str comparisons took " + (System.currentTimeMillis() - time) + " ms");
time = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
if (contentEquals(fooSb,barSb)) continue;
}
System.out.println("sb comparisons took " + (System.currentTimeMillis() - time) + " ms");
/* repeat the test as we know JVM is warmed up by now */
time = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
if (foo.equals(bar)) continue;
}
System.out.println("str comparisons took " + (System.currentTimeMillis() - time) + " ms");
time = System.currentTimeMillis();
for (int i = 0; i < 2000000000; i++) {
if (contentEquals(fooSb,barSb)) continue;
}
System.out.println("sb comparisons took " + (System.currentTimeMillis() - time) + " ms");
}
}
有结果:
true
false
true
str comparisons took 1244 ms
sb comparisons took 11530 ms
str comparisons took 1231 ms
sb comparisons took 12098 ms