1

可能重复:
为什么 + 在 Java 中与字符串一起使用?

以下语句在 Java 中有效。

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

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

虽然tmp是 String 类型并且a是 type int,但是进行了连接(即使 Java 不支持运算符重载)。

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

Java 不支持运算符重载。运算符重载有时是 C++ 程序中歧义的来源,Java 设计团队认为它带来的麻烦多于好处。

更多关于它。

如何String b=tmp+a;评估此声明?内部必须有一些等效的运算符重载概念。


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

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

4

3 回答 3

5

从技术上讲,这只是碰巧具有相同符号的不同运算符。它是“字符串连接运算符”;请参阅Java 语言规范的第 15.18.1 节

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

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

对于原始类型,实现还可以通过直接从原始类型转换为字符串来优化包装对象的创建。

于 2012-07-21T16:10:50.527 回答
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在可用的地方使用。

于 2012-07-21T16:12:06.420 回答
-1

编辑:即使是编译器做这个改变(我不知道),使用字符串连接比使用 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 快。

于 2012-07-21T16:11:43.257 回答