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

Mat*_*all 5 java string optimization

这个问题主要是纯粹的好奇心(并且杀了一段时间).为了具体起见,我正在特别询问Java.

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

String s = "any old string";
s += "";
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*ers 16

这是字节码时间!

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

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" + "";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

}