【问题标题】:Concatenating Strings in Java [duplicate]Java中的连接字符串[重复]
【发布时间】:2012-07-21 16:08:51
【问题描述】:

可能重复:
Why does + work with Strings in Java?

以下语句在 Java 中有效。

int a=50;
String tmp="a = ";
String b=tmp+a;

String 类型的b 现在包含a = 50(作为字符串)。

虽然tmp 是String 类型,aint 类型,但还是会进行连接(即使Java 不支持运算符重载)。

Java 不支持运算符重载的原因之一(与其他语言一样。事实上,我对任何语言都没有深入的了解)。

Java 不支持运算符重载。运算符重载有时是 C++ 程序中的歧义,Java 设计团队认为它造成的麻烦比 益处。

More关于它。

如何评估此语句String b=tmp+a;Operator Overloading 内部一定有一些等价的概念。


只有一个问题:我们能否从字面上理解它是如何实现的,或者我们应该相信“这只是语言的一个特性”?

我听说 Java 编译器使用 StringBuilder/StringBuffer(使用 append() 方法)来实现这一点,但我不确定。

【问题讨论】:

标签: java string operator-overloading string-concatenation


【解决方案1】:

从技术上讲,这只是碰巧具有相同符号的不同运算符。它是“字符串连接运算符”;见section 15.18.1 of the Java Language Specification

关于实施,JLS 有这样的说法:

实现可以选择执行转换和连接 一步避免创建然后丢弃中间体 String 对象。提高重复字符串的性能 连接,Java 编译器可以使用 StringBuffer 类或 减少中间String对象数量的类似技术 通过评估表达式创建的。

对于原始类型,实现也可以优化掉 通过直接从原语转换来创建包装器对象 输入一个字符串。

【讨论】:

  • tmp+a==new StringBuilder().append(tmp).append(a).toString();?如前所述here.
  • @Tiny:是的,JLS 允许实现做类似的事情(虽然我猜它更像new StringBuilder(tmp).append(a.toString()))。
【解决方案2】:

Java 不允许 用户定义 运算符重载。语言规范可以定义它想要的任何运算符:)

是的,你可以看到它是如何在内部完成的——使用javap -c 来反汇编类。例如,在我的机器上,您的代码编译为:

   0: bipush        50
   2: istore_1
   3: ldc           #2    // String a =
   5: astore_2
   6: new           #3    // class java/lang/StringBuilder
   9: dup
  10: invokespecial #4    // Method java/lang/StringBuilder."<init>":()V
  13: aload_2
  14: invokevirtual #5    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  17: iload_1
  18: invokevirtual #6    // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  21: invokevirtual #7    // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  24: astore_3
  25: return

虽然有些细节是特定于实现的;特别是,Sun/Oracle 编译器使用使用StringBuffer,但现在在可用的情况下使用StringBuilder

【讨论】:

【解决方案3】:

编辑:即使是编译器做这个改变(我不知道),使用字符串连接比使用 StringBuilder 更慢。(错误 => 不,编译器不使用StringBuilder/StringBuffer)。您只需创建一个简单的基准就可以对其进行测试。 + 运算符在 Java 中为字符串“重载”,但该语言不支持运算符重载。

尝试这样的方法来测试 StringBuilder/StringBuffer 的东西:

String str = "";
StringBuffer sbf = new StringBuffer();
StringBuilder sb = new StringBuilder();

int nTests = 100;
int nConcats = 1000;

long initialTime = 0L;
long afterStrTime = 0L;
long afterSbfTime = 0L;
long afterSbTime = 0L;

for ( int i = 0; i < nTests; i++ ) {

    initialTime = System.currentTimeMillis();
    str = "";
    sbf = new StringBuffer();
    sb = new StringBuilder();

    for ( int j = 0; j < nConcats; j++ ) {
        str += "foo"; // or str = str + "foo"
    }
    afterStrTime = System.currentTimeMillis();

    for ( int j = 0; j < nConcats; j++ ) {
        sbf.append( "foo" );
    }
    afterSbfTime = System.currentTimeMillis();

    for ( int j = 0; j < nConcats; j++ ) {
        sb.append( "foo" );
    }
    afterSbTime = System.currentTimeMillis();

}

System.out.printf( "%d milliseconds to perform %d concatenations on String\n", afterStrTime - initialTime, nConcats );
System.out.printf( "%d milliseconds to perform %d concatenations on StringBuilder\n", afterSbfTime - afterStrTime, nConcats );
System.out.printf( "%d milliseconds to perform %d concatenations on StringBuffer\n",  afterSbTime - afterSbfTime, nConcats );

你会看到 StringBuilder 可以比 StringBuffer 快,因为它不是同步的(StringBuffer 是),而且两者都比 String 快。

【讨论】:

  • 您可以通过编译问题中给出的代码然后在其上运行javap -c 来测试它,这清楚地显示它使用StringBuilder
  • @JonSkeet,好的,但是你能解释一下为什么在我上面的代码中字符串连接不如 StringBuffer 快吗?如果编译器更改为 StringBuffer,执行应该同样快你不同意吗?
  • 因为它为循环的每次迭代实例化一个StringBuilder,而你只实例化一次。
  • 所以,即使改变,它也更慢。说拼接字符串和追加到StringBuffer中是不一样的。
  • tmp+a==new StringBuilder().append(tmp).append(a).toString();?正如提到的here
猜你喜欢
  • 1970-01-01
  • 2015-07-31
  • 2019-01-16
  • 2011-05-14
  • 2014-07-23
  • 2012-02-02
  • 2014-05-20
  • 2017-06-21
  • 2013-03-02
相关资源
最近更新 更多