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

问题描述 投票:0回答:4

1.

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

2.

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

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

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

java string optimization
4个回答
14
投票

这已包含在 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

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
,如果我没看错的话,这意味着这个字符串既被存储又被内联,正如你所期望的那样) :

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

3
投票

在这种情况下,编译器将对两者进行相同的处理。

任何时候在编译时定义字符串,Java 都会优化字符串的存储。

如果在运行时定义字符串,Java 无法进行相同的优化。


-2
投票

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

如果您真的关心 String 性能并且会一遍又一遍地重复使用相同的字符串,您应该看看 string 类上的 intern 方法。

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

© www.soinside.com 2019 - 2024. All rights reserved.