这个问题主要是纯粹的好奇心(并且杀了一段时间)。我是为了具体而专门询问Java。
如果我将字符串(任何字符串)与空字符串连接起来,例如在内存中会发生什么,例如:
String s = "any old string";
s += "";
我知道之后,s的内容仍然是“任何旧字符串”,因为空的ASCII字符串作为ASCII空存储在内存中(因为,至少在Java中,字符串总是以空字符结尾) 。但是我很想知道Java(编译器?VM?)是否执行了足够的优化来知道s将不会改变,并且它可以完全省略字节码中的那条指令,或者如果在编译和运行时发生了不同的事情。
答案 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.