字符串连接: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);
    }
}

原文由 shsteimer 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 708
2 个回答

不,不完全是。

首先,语义上略有不同。 If a is null , then a.concat(b) throws a NullPointerException but a+=b will treat the original value of a 好像是 null 。此外, concat() 方法仅接受 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 时可能会发生变化。来自 @lukasederHotSpot JVM 内在函数列表

原文由 Tom Hawtin - tackline 发布,翻译遵循 CC BY-SA 3.0 许可协议

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 方法,否则使用 + 。但是,性能差异应该可以忽略不计,您可能不应该为此担心。

原文由 Eli Courtwright 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题