情况1:
String str = "StackOverFlow"; String str1 = "StackOverFlow"; if(str==str1){ System.out.println("equal");//prints equal }
案例二:
String str = "StackOverFlow"; String str1=str.intern(); if(str==str1){ System.out.println("equal");//prints equal }
跟进问题:
我想知道对于第一种情况JVM是否在
intern()
内部调用并将引用分配str
给str1
?在第一种情况下两个引用如何相等?
第一种情况是否意味着每当您声明一个字符串,就像
String str = "StackOverFlow";
它添加到字符串池中一样与intern()
方法相同?是否由堆外使用
String str = "StackOverFlow";
并分配的字符串池?intern()
如果是,具体在哪里?
对于问题 4,答案如下:
在 Java 6 及更早版本中,实习字符串也存储在永久代中。在 Java 7 中,interned 字符串存储在主对象堆中。
这是文档中的内容:
在 JDK 7 中,interned 字符串不再分配在 Java 堆的永久代中,而是与应用程序创建的其他对象一起分配在 Java 堆的主要部分(称为年轻代和年老代)中. 此更改将导致更多数据驻留在主 Java 堆中,而永久代中的数据更少,因此可能需要调整堆大小。由于此更改,大多数应用程序只会看到相对较小的堆使用差异,但加载许多类或大量使用该
String.intern()
方法的大型应用程序将看到更显着的差异。
更多细节来自这里:
Java 6 中的 String.intern()
在过去的美好时光里,所有的实习字符串都存储在 PermGen 中——堆的固定大小部分,主要用于存储加载的类和字符串池。除了显式嵌入的字符串之外,PermGen 字符串池还包含您程序中之前使用的所有文字字符串(这里使用了重要的词——如果从未加载/调用过类或方法,则不会加载其中定义的任何常量)。
The biggest issue with such string pool in Java 6 was its location – the PermGen. PermGen has a fixed size and can not be expanded at
运行。您可以使用 -XX:MaxPermSize=96m 选项进行设置。据我所知,默认 PermGen 大小在 32M 到 96M 之间变化,具体取决于平台。您可以增加它的大小,但它的大小仍然是固定的。这种限制需要非常小心地使用 String.intern——你最好不要使用这种方法来实习任何不受控制的用户输入。这就是为什么在 Java 6 时代字符串池主要是在手动管理的映射中实现的。
Java 7 中的 String.intern()
Oracle 工程师对 Java 7 中的字符串池逻辑进行了极其重要的更改——将字符串池重新定位到堆中。这意味着您不再受单独的固定大小内存区域的限制。所有字符串现在都位于堆中,就像大多数其他普通对象一样,这允许您在调整应用程序时仅管理堆大小。从技术上讲,仅此一项就足以成为重新考虑在 Java 7 程序中使用 String.intern() 的充分理由。但还有其他原因。