字符串常量池,新对象初始化(使用new关键字)与字符串的正常初始化?

时间:2015-05-12 06:37:35

标签: java string

String s1 = new String("abc");
String s2 = "abc";

s1中,将创建两个对象,一个在字符串池中,另一个在非池内存中。

s2中,字符串池中只会创建一个对象。

如果我们这样做:

s1.concat("def");
s2.concat("def");

现在字符串池中有3个对象("abc""def""abcdef"),其中两个被放弃("def""abcdef")离开{ {1}}在记忆中。

两个引用都引用了一个字符串池对象。

记忆对象有什么意义?

2 个答案:

答案 0 :(得分:4)

  

s2中,字符串池中只会创建一个对象。

实际上不行,这一行不会创建新对象。 s2将引用用于构造s1的相同常量。

  

现在字符串池中有3个对象("abc""def""abcdef"),其中两个被放弃("def""abcdef")离开{ {1}}在记忆中。

不,只有"abc""abc"在常量池中,并且因为它们是常量,所以它们将在程序的持续时间内保留在内存中。 "def"将在构建后立即进行垃圾收集,因为它永远不会存储在任何地方。

如果您使用"abcdef"运算符而不是+,编译器实际上会将两个常量字符串合并为一个,并且只将结果字符串存储在池中。

  

两个引用都引用了一个字符串池对象。

不,只有String.concat()引用常量池中的字符串,s2的结果都不会出现在常量池中。

  

记忆对象有什么意义?

您是否在询问字符串常量池的含义是什么?它本质上只是一种优化,允许常量(即代码中的.concat() - ed字符串)共享相同的引用,以避免构建大量相同的实例。因为它们是常量,所以这可以在编译时完成,在运行时节省空间和时间。这不适用于在运行时构造的任何字符串,除非您明确调用.intern(),但通常应该avoid doing so

您可能也对Where does Java's String constant pool live, the heap or the stack?

感兴趣

编辑:因为你坚持认为你的例子中的"将成为常量池的一部分,所以这里的简单证据并非如此:

"abcdef"

您可以清楚地看到,字符串$ javac -version javac 1.7.0_02 $ cat Test.java public class Test { public static void main(String[] args) { String s1 = "123" + "456"; String s2 = "abc".concat("def"); } } $ javac Test.java $ javap -c -classpath . Test Compiled from "Test.java" public class Test { public Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String 123456 2: astore_1 3: ldc #3 // String abc 5: ldc #4 // String def 7: invokevirtual #5 // Method java/lang/String.concat:(Ljava/lang/String;)Ljava/lang/String; 10: astore_2 11: return } 123456abc是常量(请参阅ldc),并在运行时调用def

答案 1 :(得分:2)

s1.concat("def");s2.concat("def");在运行时发生,它们不会成为常量池的一部分,它们会转到

请注意concat的签名:

public String concat(String str)

它会返回 new 字符串,而您不会将该字符串分配给任何变量。

  

记忆对象有什么意义?

目前还不清楚你在问什么,但请注意,由于concat创建的字符串未被分配(对它的引用被丢弃),它将有资格进行垃圾回收。