1. String 中 诡异的 intern() 方法
在学习String的intern()方法时,有一些疑惑和不解的地方,特此记录
-
intern()方法的官方描述
如果一个字符串不存在常量池中,那么把其放入常量池,并返回指向常量池中该字符串的地址。
如果其在常量池中,那么直接返回常量池中该字符串的地址。
有以下代码段。
![]()
其中第一个 == 判断显然是返回 false ,因为 s 指向堆中的字符串对象 "1",而 s2 指向字符串常量池中的 "1"。
关键在于下面的一段代码,在 jdk6 和 jdk7/8 中的输出是不同的,在jdk6中输出 false ,在 jdk 7/8中输出true。
乍一看,似乎和上面没有什么不同,只是 字符串由 "1" 变成了 "11", 那么结果不应该是还是为 false 吗,为什么
jdk6 中是false ,jdk 7/8中会变成 true 呢? 为了明白这个问题,我们首先需要知道什么时候字符串常量会被放入字符串常量池中。
-
字符串常量
在上述代码的
String s = new String("1");时,字符串常量 "1" 被放入到了字符串常量池中,而在 代码
String s3 = new String("1") + new String("1");时,字符串 "11" 并未放入字符串常量池中。在jdk6中,由于 字符串常量池在 永久代中,因此在执行代码
s3.intern();时, 会将字符串 "11" 放入字符串常量池中那么自然,s4 会指向 字符串常量池中的 "11" , s3指向的是堆中的 字符串对象 "11" ,他们相比较,结果为false。
在 jdk7/8 中,做了一个重大的改进,将 字符串常量池中 移动到了 堆中。 可能正是由于这点才会对 字符串 常量池做了一定的"优化",
调用 intern()方法,如果该字符串在串池中,则返回该地址,否则,在字符串常量池中,生成一个指向该字符串对象的引用!
具体可以参见下图:
![]()
![]()
所以,该段代码在 在 jdk7/8 中 执行结果会为false.
-
练习
String s3 = new String("1") + new String("1"); s3.intern(); String s4 = "11"; System.out.println(s3 == s4);//true String s5 = new String("1") + new String("1"); s5.intern(); String s6 = "11"; System.out.println(s5 == s6);//false System.out.println(s5 == s3);//false System.out.println(s6 == s3);//true System.out.println(s6 == s4);//true根据上面的知识, 我们知道 s3和s4都指向堆中的 "11",故结果为 true
s5指向自己创建的堆中的对象(和s3指向的不同),而s6指向的是s3指向的那个对象。
因此 s5 == s6 为 false, s5 == s3为 false, 而 s6 == s3, s6 == s4返回 true
总结





浙公网安备 33010602011771号