最近在猛学虚拟机(三天打鱼两天晒网),很久之前就想写一篇关于String 中 intern 的帖子了,实在是懒呀懒差点都忘了咋用了,最近又学习了一遍总结如下:
jdk6 中,将这个字符串对象尝试放入串池.
如果串池中有,则并不会放入。只会返回已有的串池中的对象地址
如果没有,则会把对象的复制一份,放入串池,并返回串池中的对象
jdk7 起,将这个字符串对象尝试放入串池(jdk8 也是如下方式).
如果串池中有,则并不会放入。只会返回已有的串池中的对象地址
如果没有,则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址
我们先来看一个例子了解了解:
public class Test { public static void main(String[] args) { String s = new String("1"); s.intern(); String s2 = "1"; System.out.println(s == s2); String s3 = new String("a") + new String("b"); s3.intern(); String s4 = "ab"; System.out.println(s3 == s4); } }运行结果如下:
会发现这里又new 了一个新对象,而这个新对象只在堆里面有值而在字符串常量池是没有值的。
大家如上所示的图看看这个s 和 s2地址都不一样,自然就返回false 了。首先 执行 new String("1") 时会在堆内和串池中都产生一个值为“1” 的对象。而此时s.intern() 其实对s 本身啥都没做,而 String s2 = "1"; 相当于在堆内产生了新的对象
我来解释下上图,首先s3在堆内new 了一个对象地址为0x002,此后执行了 s3.intern(), 会先去串池里面找一下是否存在 "ab",此时发现不存在.
则会把对象的引用地址复制一份,放入串池,此时串池里面存储的是 "ab" 的地址,而不是对象,而s4 = "ab"; 此时先会去串池里面找“ab”,此时发现已经存在对应的引用,所以返回的就是s3 对象的地址
接下来我们继续看看这个例子:
public class Test { public static void main(String[] args) { String s3 = new String("a") + new String("b"); String s5= s3.intern(); String s4 = "ab"; System.out.println(s3 == s4); //true System.out.println(s5 == s4); //true } }
这里我特别提及一下s5是咋来的,根据我们上面说的“如果没有,则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址” ,在执行"s3.intern()"操作后,在这里s5发现在串池中没有字符串"ab" 便将"ab" 在堆中的引用复制一份到串池去,同步返回引用对象的地址,然后s5 同步接收到
接下来我们再看看这个例子:
public class Test { public static void main(String[] args) { String s3 = new String("a") + new String("b"); String s5= s3.intern(); System.out.println(s3 == "ab"); System.out.println(s5 == "ab"); } }结果是啥?我给个答案 true true,这里 =="ab",其实和String s4="ab"; ,然后 System.out.println(s3 == s4); 类似
以上是我个人使用jdk8 跑出来的结果,至于jdk6 我是在没有环境就暂时多理解下概念吧~(还是太懒了),后期还会更新的,如有问题麻烦告诉我我们一起多探讨下,我也是个菜逼~