String s1 = new String("abc");
String s2 = "abc";
在s1
中,将创建两个对象,一个在字符串池中,另一个在非池内存中。
在s2
中,字符串池中只会创建一个对象。
如果我们这样做:
s1.concat("def");
s2.concat("def");
现在字符串池中有3个对象("abc"
,"def"
和"abcdef"
),其中两个被放弃("def"
和"abcdef"
)离开{ {1}}在记忆中。
两个引用都引用了一个字符串池对象。
记忆对象有什么意义?
答案 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
}
,123456
和abc
是常量(请参阅ldc
),并在运行时调用def
答案 1 :(得分:2)
s1.concat("def");
和s2.concat("def");
在运行时发生,它们不会成为常量池的一部分,它们会转到堆。
请注意concat
的签名:
public String concat(String str)
它会返回 new 字符串,而您不会将该字符串分配给任何变量。
记忆对象有什么意义?
目前还不清楚你在问什么,但请注意,由于concat
创建的字符串未被分配(对它的引用被丢弃),它将有资格进行垃圾回收。