字符串实习在Java 7+中如何工作?

时间:2014-11-30 05:14:28

标签: java string jvm heap string-interning

所以,我意识到我要提出的问题涉及到一次又一次被打死的话题,然而,即使在阅读了我能找到的所有答案和文档之后,我也会#39 ; m仍然对字符串实习感到困惑。也许是因为我对JVM缺乏了解;也许是因为Java 7中引入的变化使许多上述答案和文档贬值。无论哪种方式,我都被困住了,我希望有人可以帮助我更清楚地理解这个概念......

String a = "text";
String b = new String("text");

在上面的例子中,我理解将创建两个String对象。我也明白在内存中只有一个包含序列't', 'e', 'x', and 't'的char数组。

但是,内存中的每个字符串对象实际存储在哪里?

如果我读过的内容我已经正确阅读:变量a的引用将存储在常量池中,而b的引用将存储在堆中, 对?

如果是这种情况,我对实习池如何维护实习字符串感到困惑。它是否跟踪常量池中定义的字符串以及已从堆中手动实现(调用.intern())的字符串? JVM是否创建常量池中定义的字符串对象并将它们加载到实习池中?我对这一切的运作方式感到困惑......

再次,对于提出这样令人困惑/愚蠢的问题感到遗憾,这只是因为我对JVM的结构和内部运作相对较新,而且其中很多都离开了头部旋转。谢谢!

2 个答案:

答案 0 :(得分:8)

当你声明:

时,java中有一个名为String Memory Pool的东西
String str1="abc";

它转到那个内存池而不是堆上。但是当你写道:

String str2=new String("abc");

它在堆上创建一个完整的对象,如果你再次写:

String str3 = "abc"; 

它不会在池上创建任何更多对象,如果该文字已经存在,它将检查池,它会将其分配给它。但写作:

String str4 = new String("abc");

将再次在堆上创建一个新对象

关键是:

在写入时,将始终在堆上创建一个新对象:

new String("abc");

但是如果你在不使用关键字new的情况下直接分配字符串,它将只从内存池中引用(或者如果内存池中不存在则创建)

intern()方法查找字符串是否存在于内存池中,如果不存在,则将其添加到内存池并返回对它的引用。因此在使用此方法之后,您的String引用不指向堆上的任何对象,它指向String Memory Pool中的对象(另请注意,内存池仅包含唯一的字符串)。

答案 1 :(得分:6)

当您说new String()时,您会获得新的Object参考,请考虑

String a = "text";
String b = new String("text");
System.out.println(a == b);
b = b.intern();
System.out.println(a == b);

然后第一个a == b会显示false,因为它们是不同的引用。如果我们intern() bb = b.intern(),我们可以再次测试并获得true。我希望有所帮助。从版本1.0开始,上面的代码在Java中的工作方式相同(现在它仍然在Java 8中以这种方式工作)。