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

所以,我意识到我要问的问题与一个一次又一次被打死的话题有关,但是,即使在阅读了我能找到的所有答案和文档之后,我仍然对字符串实习感到困惑。也许是由于我对JVM缺乏了解;也许是由于Java 7中引入的更改贬低了上述许多答案和文档。无论哪种方式,我都被困住了,我希望有人能帮助我更清楚地理解这个概念......

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

在上面的示例中,我知道将创建两个 String 对象。我还知道,内存中将只有一个包含该序列的 char 数组。't', 'e', 'x', and 't'

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

如果我读过的内容我读对了:变量的引用将存储在常量池中,而的引用将存储在堆中,对吧?ab

如果是这样的话,我对实习生池如何维护实习字符串感到困惑。它是否跟踪常量池中定义的字符串以及已从堆中手动暂存(调用)的字符串?JVM 是否创建在常量池中定义的字符串对象,并将它们加载到实习池中?我对它是如何工作的感到困惑....intern()

再次,很抱歉问了这么令人困惑/令人不安的问题,只是我对它的结构和内部运作相对较新,而且很多问题都让我头晕目眩。谢谢!JVM


答案 1

在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 引用不会指向堆上的任何对象,而是指向字符串内存池中的对象(另外,请注意,内存池仅包含唯一字符串)。


答案 2

当你说你得到了一个新的参考,所以考虑new String()Object

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

然后首先将显示,因为它们是不同的引用。如果我们说我们可以再次测试并得到.我希望这有帮助。自1.0版本以来,上面的代码在Java中的工作方式相同(今天在Java 8中仍然以这种方式工作)。a == bfalseintern()bb = b.intern()true