package com.zhb.jvm;
/**
*
* @author zhb
*
*/
public class RuntimeConstantPoolOOM {
public static void main(String[] args){
String str1 = "abc";
System.out.println(str1.intern() == str1); //true
String str2 = new String("abcd");
System.out.println(str2.intern() == str2); //false
String str3 =new StringBuilder("math").append("analyze").toString();
System.out.println(str3.intern() == str3); //true
String str4 =new StringBuilder("computer").append("software").toString();
System.out.println(str4.intern() == str4); //true
String str5 =new StringBuilder("jav").append("a").toString();
System.out.println(str5.intern() == str5); //false
}
}
首先,我们可以知道intern()方法的定义。 intern的定义:当调用intern方法时,如果池已经包含等于equals(Object)方法确定的thisString对象的字符串,则返回池中的字符串。否则,将thisString对象添加到池中,并返回对此String对象的引用。
str1.intern == str1为true。这很容易理解。 str2.intern()== str2这个方法的定义也很容易理解。 但是为什么str3.intern()== str3是真的。事实上,我认为它的定义是错误的。 str5.intern()== str5与false相反。 我在终端上运行命令 java -version java版“1.7.0_40” Java(TM)SE运行时环境(版本1.7.0_40-b43) Java HotSpot(TM)64位服务器VM(内置24.0-b56,混合模式)
我想获得正确答案。非常感谢你!
答案 0 :(得分:1)
为什么str3.intern()== str3为真
因为,正如你所说:
否则,将thisString对象添加到池中,并返回对此String对象的引用。
你就是这样。该池还不包含str3(即“mathanalyze”)。所以str3被添加到池中并返回。
对于str5,你是另一种情况:
如果池已经包含等于thisString对象的字符串(由equals(Object)方法确定),则返回池中的字符串
因此,当代码执行时,池已经包含字符串“java”,这并不奇怪,因为java是,例如,所有标准类的顶级包的名称,以及名称用于启动JVM的可执行文件。文本字符串“java”很可能用于引导应用程序并在执行main方法之前加载类的代码。
答案 1 :(得分:1)
我看到它的方式,我会说默认情况下字符串"java"
在池中。实际上,当你在str3
上调用intern()时,这个单词还没有在池中,所以它被添加并且返回的引用是str3
(没有创建新对象),所以测试给出了true。相反,"java"
已经在池中,因此它返回池中对象的引用,这与str5
的引用不同。
请注意,您不仅会使用"java"
,还会使用所有单个字符来观察相同的行为。
答案 2 :(得分:0)
测试foo.intern() == foo
是一种在foo
被调用之前测量intern()
是否已在池中的方法。因此str3.intern() == str3
表示str3
尚未在池中。就是这样。
在复制之前,运行时中某处可能存在一个常量字符串"java"
,这就是str5.intern() != str5
的原因。
以下是通过grepping OpenJDK 8源代码找到的最明显的案例:
./com/sun/beans/decoder/DocumentHandler.java: setElementHandler("java", JavaElementHandler.class); // NON-NLS: the element name
./com/sun/tools/example/debug/gui/JDBMenuBar.java: JDBFileFilter filter = new JDBFileFilter("java", "Java source code");
./com/sun/tools/jdi/SunCommandLineLauncher.java: "java",
./sun/launcher/LauncherHelper.java: (progname == null) ? "java" : progname ));
./sun/rmi/server/Activation.java: File.separator + "bin" + File.separator + "java";
./sun/rmi/server/Activation.java: command[0] = "java";
答案 3 :(得分:0)
据我所知,可能有任何运行时字符串" java" ,这会导致这个问题。
String str5 =new StringBuilder("jav").append("a").toString();
System.out.println(str5.intern() == str5); //false
以上两个语句仅为false
,除了您希望与true
一起传递的任何其他字符串。
符合Java规范的Intern()。
这将返回字符串对象的规范表示。最初为空的字符串池由String类私有维护。调用实习方法时,如果池已经包含等于此字符串对象的字符串(由equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回对此String对象的引用。因此,对于任何两个字符串s和t,当且仅当s.equals(t)为真时,s.intern()== t.intern()才为真。
所有文字字符串和字符串值常量表达式都是实体。字符串文字在The Java™Language Specification。的第3.10.5节中定义。
<强>返回强>: 与此字符串具有相同内容的字符串,但保证来自唯一字符串池。
希望它会对你有所帮助。