假设字符串 a 和 b:
a += b a = a.concat(b)
在引擎盖下,它们是一样的吗?
这里是 concat 反编译作为参考。我也希望能够反编译+运算符以查看它的作用。
+
public String concat(String s) { int i = s.length(); if (i == 0) { return this; } else { char ac[] = new char[count + i]; getChars(0, count, ac, 0); s.getChars(0, i, ac, count); return new String(0, count + i, ac); } }
不,不完全是。
首先,语义上略有不同。如果a是null,则a.concat(b)抛出 aNullPointerException但a+=b会将 的原始值a视为null。此外,该concat()方法仅接受String值,而+运算符将默默地将参数转换为字符串(使用toString()对象的方法)。因此,该concat()方法在接受的内容上更加严格。
a
null
a.concat(b)
NullPointerException
a+=b
concat()
String
toString()
要深入了解,请编写一个简单的类a += b;
a += b;
public class Concat { String cat(String a, String b) { a += b; return a; } }
现在用javap -c(包含在 Sun JDK 中)反汇编。您应该会看到一个列表,其中包括:
javap -c
java.lang.String cat(java.lang.String, java.lang.String); Code: 0: new #2; //class java/lang/StringBuilder 3: dup 4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V 7: aload_1 8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 11: aload_2 12: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: invokevirtual #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/ String; 18: astore_1 19: aload_1 20: areturn
所以,a += b等价于
a += b
a = new StringBuilder() .append(a) .append(b) .toString();
该concat方法应该更快。但是,如果字符串越多,该StringBuilder方法就会获胜,至少在性能方面是这样。
concat
StringBuilder
String和StringBuilder(及其包私有基类)的源代码可在 Sun JDK 的 src.zip 中找到。您可以看到您正在构建一个 char 数组(根据需要调整大小),然后在创建 final 时将其丢弃String。在实践中,内存分配速度惊人。
更新: 正如 Pawel Adamski 所说,最近的 HotSpot 的性能发生了变化。javac仍然产生完全相同的代码,但字节码编译器作弊。简单的测试完全失败,因为整个代码体都被丢弃了。Summing System.identityHashCode(not String.hashCode) 显示StringBuffer代码有一点优势。下一次更新发布或您使用不同的 JVM 时可能会发生变化。
javac
System.identityHashCode
String.hashCode
StringBuffer