在Java中连接空字符串时,在编译和运行时会发生什么?

时间:2009-07-27 19:12:09

标签: java string optimization

这个问题主要是纯粹的好奇心(并且杀了一段时间)。我是为了具体而专门询问Java。

如果我将字符串(任何字符串)与空字符串连接起来,例如在内存中会发生什么,例如:

String s = "any old string";
s += "";

我知道之后,s的内容仍然是“任何旧字符串”,因为空的ASCII字符串作为ASCII空存储在内存中(因为,至少在Java中,字符串总是以空字符结尾) 。但是我很想知道Java(编译器?VM?)是否执行了足够的优化来知道s将不会改变,并且它可以完全省略字节码中的那条指令,或者如果在编译和运行时发生了不同的事情。

2 个答案:

答案 0 :(得分:16)

这是字节码时间!

class EmptyString {
    public static void main(String[] args) {
        String s = "any old string";
        s += "";
    }
}

javap -c EmptyString

Compiled from "EmptyString.java"
class EmptyString extends java.lang.Object{
EmptyString();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String any old string
   2:   astore_1
   3:   new     #3; //class java/lang/StringBuilder
   6:   dup
   7:   invokespecial   #4; //Method java/lang/StringBuilder."":()V
   10:  aload_1
   11:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   14:  ldc     #6; //String
   16:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22:  astore_1
   23:  return

}

您可以看到+=导致创建StringBuilder,无论它连接的是什么,因此无法在运行时进行优化。

另一方面,如果将两个String文字放在同一个表达式中,它们会被编译器连接起来:

class EmptyString {
    public static void main(String[] args) {
        String s = "any old string" + "";
    }
}

javap -c EmptyString

Compiled from "EmptyString.java"
class EmptyString extends java.lang.Object{
EmptyString();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String any old string
   2:   astore_1
   3:   return

}

答案 1 :(得分:2)

执行

行后你会得到一个新的字符串
s += "";

Java在字符串连接后分配一个新的String对象并将其分配给 s 。如果你有eclipse方便(我假设你可以在NetBeans中做同样的事情,但我只使用过eclipse)你可以断点那条线并观察 s 点对象的对象ID在执行该行之前和之后。在我的例子中,该行代码之前的 s 的对象ID是id = 20,之后是id = 24.