Java编译器是否有效地处理内联字符串?

时间:2009-07-23 13:12:02

标签: java string optimization compiler-construction

1

static final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);

2

System.out.println("Efficiently stored String");

Java编译器会以同样的方式处理这些(1和2)吗?

仅供参考:有效地,我指的是运行时内存利用率以及代码执行时间。例如第一种情况可以在堆栈上加载变量memFriendly吗?

4 个答案:

答案 0 :(得分:14)

Java Language Spec

中介绍了这一点
  

每个字符串文字都是一个参考   (§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

答案 1 :(得分:5)

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,如果我正在读取此权利则意味着正如您所料,这个String既存储又内联:

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

答案 2 :(得分:3)

在这种情况下,编译器将处理两者。

无论何时在编译时定义String,Java都将优化字符串的存储。

如果在运行时定义了字符串,则Java无法进行相同的验证。

答案 3 :(得分:-2)

您拥有的代码是等效的,因为字符串文字会由编译器自动实现。

如果你真的关心字符串性能并且会反复使用相同的字符串,那么你应该看一下字符串类的intern方法。

http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()