1.
static final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
2.
System.out.println("Efficiently stored String");
Java 编译器会以相同的方式处理这两者(1 和 2)吗?
仅供参考:我所说的高效指的是运行时内存利用率以及代码执行时间。例如第一种情况可以在堆栈上花费更多时间来加载变量 memFriendly 吗?
这已包含在 Java 语言规范中:
每个字符串文字都是一个引用 (§4.3) 到实例 (§4.3.1, §12.5) String 类(第 4.3.3 节)。细绳 对象具有恒定的值。细绳 文字,或者更一般地说,字符串 这是常数的值 表达式 (§15.28) - 被“拘禁”,因此 为了共享独特的实例,使用 String.intern 方法。
您还可以使用 javap 工具亲自查看。
对于此代码:
System.out.println("Efficiently stored String");
final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
javap 给出以下内容:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Efficiently stored String
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #3; //String Efficiently stored String
13: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
public static void main(String[] args) {
System.out.println("Hello world!");
String hola = "Hola, mundo!";
System.out.println(hola);
}
以下是 javap 显示的该代码的反汇编内容:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String Hello world!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //String Hola, mundo!
10: astore_1
11: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
14: aload_1
15: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: return
看起来第二个字符串正在被存储,而第一个字符串只是直接传递给方法。
这是用 Eclipse 的编译器构建的,这可能解释了我的答案和 McDowell 的答案的差异。
更新:这是如果
hola
被声明为 final
的结果(结果是没有 aload_1
,如果我没看错的话,这意味着这个字符串既被存储又被内联,正如你所期望的那样) :
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String Hello world!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //String Hola, mundo!
10: astore_1
11: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
14: ldc #30; //String Hola, mundo!
16: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
19: return
在这种情况下,编译器将对两者进行相同的处理。
任何时候在编译时定义字符串,Java 都会优化字符串的存储。
如果在运行时定义字符串,Java 无法进行相同的优化。
您拥有的代码是等效的,因为字符串文字是由编译器自动保留的。
如果您真的关心 String 性能并且会一遍又一遍地重复使用相同的字符串,您应该看看 string 类上的 intern 方法。
http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()