字符串连接:concat()vs“+”运算符

假设字符串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);
    }
}

不,不完全。

首先,语义有细微差别。 如果anull ,那么a.concat(b)引发一个NullPointerExceptiona+=b会治疗的原始值a就好像它是null 。 此外, concat()方法只接受String值,而+运算符将静态地将参数转换为String(对象使用toString()方法)。 所以concat()方法在它接受的方面更加严格。

为了看看底下,写一个简单的类与a += b;

public class Concat {
    String cat(String a, String b) {
        a += b;
        return a;
    }
}

现在使用javap -c (包含在Sun JDK中)进行反汇编。 你应该看到一个列表包括:

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 = new StringBuilder()
    .append(a)
    .append(b)
    .toString();

concat方法应该更快。 但是,使用更多字符串时, StringBuilder方法至少在性能方面会获胜。

StringStringBuilder (及其包私有基类)的源代码可在Sun JDK的src.zip中找到。 你可以看到你正在建立一个char数组(根据需要调整大小),然后在创建最终String时将其扔掉。 实际上,内存分配非常快。

更新:正如Pawel Adamski所指出的,在最近的HotSpot中,性能发生了变化。 javac仍然会生成完全相同的代码,但字节码编译器会作弊。 简单的测试完全失败,因为整个代码都被扔掉了。 总结System.identityHashCode (不是String.hashCode )显示StringBuffer代码具有轻微的优势。 如果下次更新发布,或者您使用其他JVM,可能会有所变化。 来自@lukaseder,一个HotSpot JVM内部函数列表。


Niyaz是正确的,但值得注意的是,特殊的+运算符可以被Java编译器转换为更高效的东西。 Java有一个StringBuilder类,它表示一个非线程安全的可变字符串。 在执行一串String连接时,Java编译器会自动转换

String a = b + c + d;

String a = new StringBuilder(b).append(c).append(d).toString();

这对于大型弦乐来说效率更高。 据我所知,当你使用concat方法时不会发生这种情况。

但是,将空字符串连接到现有字符串时,concat方法更有效。 在这种情况下,JVM不需要创建一个新的String对象,并且可以简单地返回现有的对象。 请参阅concat文档以确认这一点。

因此,如果您对效率超级关注,那么在连接可能为空的字符串时应该使用concat方法,否则使用+。 但是,性能差异应该可以忽略不计,您可能不应该担心这一点。


我运行了一个类似于@marcio的测试,但用下面的循环代替:

String c = a;
for (long i = 0; i < 100000L; i++) {
    c = c.concat(b); // make sure javac cannot skip the loop
    // using c += b for the alternative
}

为了更好的衡量,我也投入了StringBuilder.append() 。 每次测试运行10次,每次运行100k次。 结果如下:

  • StringBuilder胜出。 大多数运行的时钟时间结果为0,最长时间为16ms。
  • a += b每次运行需要大约40000ms(40s)。
  • concat每次运行只需要10000ms(10s)。
  • 我没有反编译该类以查看内部结构或通过分析器运行它,但我怀疑a += b花费了大量时间创建StringBuilder新对象,然后将它们转换回String

    链接地址: http://www.djcxy.com/p/24849.html

    上一篇: String concatenation: concat() vs "+" operator

    下一篇: how to alternatively concatenate 3 strings