1.
static final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
2.
System.out.println("Efficiently stored String");
Java编译器会以相同的方式处理这两种情况吗?
注:我指的是运行时内存利用率和代码执行时间的有效性。例如,第一种情况是否会在堆栈加载变量memFriendly时花费更多时间?
1.
static final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
2.
System.out.println("Efficiently stored String");
Java编译器会以相同的方式处理这两种情况吗?
注:我指的是运行时内存利用率和代码执行时间的有效性。例如,第一种情况是否会在堆栈加载变量memFriendly时花费更多时间?
这在Java语言规范中有详细说明:
每个字符串字面值都是对 String 类(§4.3.3)的实例(§4.3.1、§12.5) 的引用(§4.3)。String 对象具有恒定的值。字符串字面值或更一般地说,是常量表达式(§15.28)的值,“interned”以共享唯一实例,使用方法 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);
}
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
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
你所拥有的代码是等效的,因为字符串字面量会被编译器自动合并。
如果你真的关心字符串的性能,并且将重复使用相同的字符串,那么你应该查看字符串类中的intern方法。
http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()
intern()
”这个问题的答案在您提供的“Java词汇表”文章中已经给出——所有在编译时存在的字符串文字都会自动进行内部化。好好想一想,如果您有一个字符串,它不是在编译时存在的,而是基于某些运行时信息(用户输入、控制台参数等)变化的。如果您只创建了一次该字符串并将其传递,那么调用intern()
就没有任何意义。如果您重复创建相同的运行时字符串,则可能违反了DRY原则,最好的优化方法可能是消除重复。 - David Moles
logger.info("Log this");
,那么在方法调用中耗费的时间,特别是日志记录到磁盘上的输出将会远远超过字符串存储方式之间的速度差异。 - Grant Wagner