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

2022-08-31 04:19:07

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

答案 1

不,不完全是。

首先,语义略有不同。如果 是 ,则抛出一个,但会将的原始值视为 .此外,该方法仅接受值,而运算符将以静默方式将参数转换为 String(对对象使用该方法)。因此,该方法在接受的内容上更加严格。anulla.concat(b)NullPointerExceptiona+=banullconcat()String+toString()concat()

要查看引擎盖下,请编写一个简单的类a += b;

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

现在拆卸(包含在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 = new StringBuilder()
    .append(a)
    .append(b)
    .toString();

该方法应该更快。但是,随着字符串的增加,该方法至少在性能方面是获胜的。concatStringBuilder

和(及其包私有基类)的源代码在 Sun JDK 的 src.zip中可用。您可以看到您正在构建一个 char 数组(根据需要调整大小),然后在创建最终的 .在实践中,内存分配的速度惊人。StringStringBuilderString

更新:正如Pawel Adamski所指出的那样,在最近的HotSpot中,性能发生了变化。 仍然生成完全相同的代码,但字节码编译器作弊。简单的测试完全失败,因为整个代码主体都被丢弃了。求和(不是)表明代码有轻微的优势。在下一个更新发布时,或者如果您使用不同的 JVM,则可能会发生变化。从@lukasederHotSpot JVM内部函数的列表javacSystem.identityHashCodeString.hashCodeStringBuffer


答案 2

Niyaz是正确的,但同样值得注意的是,特殊+运算符可以通过Java编译器转换为更有效的东西。Java有一个StringBuilder类,它表示一个非线程安全的可变字符串。当执行一堆字符串串联时,Java 编译器会静默地转换

String a = b + c + d;

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

对于大字符串,这明显更有效。据我所知,当您使用concat方法时,不会发生这种情况。

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

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