文章目录
关于java中String类的intern方法
前因
复习中,写笔记的常用类这节时,以为自己搞懂了 String 的 intern 方法的含义,不就是返回字符串常量池中字符串常量的地址嘛!
String s1 = new String("zs");
String s2 = s1.intern();
System.out.println(s1 == s2);
s1 指向堆中实例,s2 指向 String Pool 中的字符串,所以肯定为 false!
查找资料时搜到了一篇博客字符串常量池深入解析_River的博客-CSDN博客_字符串常量池,看着博主有所疑问
String s3 = new String("1") + new String("1");
String s5 = s3.intern();
String s4 = "11";
System.out.println(s5 == s3);
System.out.println(s5 == s4);
System.out.println(s3 == s4);
System.out.println("======================");
String s6 = new String("go") +new String("od");
String s7 = s6.intern();
String s8 = "good";
System.out.println(s6 == s7);
System.out.println(s7 == s8);
System.out.println(s6 == s8);
s3 不就是 StringBuilder 对象调用 append 方法完成拼接最后调用 toString 方法得来的嘛,是新new的对象,而 s5 和 s4 指向 String Pool 中的 “11”,结果为
false、true、false
======================
false、true、false
这有什么难的?
但结果让我大吃一惊:
居然都是 true ,这让我想不通啊&_&
尝试
我尝试把s3.intern()这一行给注释掉,一运行结果是false???
哇,这个 intern 方法这么神奇,我开始乱想了…难不成是 intern 方法底层偷偷地把 s3 保存的地址换成了 常量池中 “11” 的内存地址。
于是马上把笔记关于 intern 的地方从头到尾的修改,修改了相关定义,但我还是觉得不大对劲,intern 这么能啊?于是再一此查看注释
其中否则,将此 String 对象添加到池中并返回对该 String 对象的引用。
这一句终于引起了我的注意,难不成使用这种拼接方式创建的String对象,并不会在池中创建"11",(只有在首次使用某字面量时,才会在池中创建),而这种new String("1")+new String("1")
使用的是"1"字面量,池中只有"1"。所以调用 intern 方法时,由于池中没有"11",就把 s3 实例引用添加到池中了,返回了 s3 实例的引用。
那么String s4 = "11";
它在 String Pool 中使用equals方法找,找了一个值为"11"的实例(引用),也就是 s3 实例,就把 s3 实例引用返回给 s4。
前提:HotSpot VM,String对象调用 intern方法,使用equals方法确定两个对象是否相等
- 在 JDK7 及以前,如果池中包含一个等于String对象的字符串,则返回字符串的地址;如果不包含此字符串,则在池中创建一个与String对象的值相同的字符串,并返回其地址。
- 在 JDK8 及以后,如果池中包含一个等于String对象的字符串,则返回字符串的地址;如果不包含此字符串,则在池中创建一个引用,这个引用指向String对象,并返回其引用。
我的是 JDK 8,由于池中的字符串每个都是唯一的,那么"11"代指的应该就是已经添加到池中的 s3 实例,而不是在池中重新创建一个字符串"11"。
那么上面三个 true 就能够理解了。
String s6 = new String("go") +new String("od");//在堆中创建了StringBuilder实例用于完成拼接、值为"go"的实例、"od"实例、"good"实例,在常量池中创建了"go","od"
String s7 = s6.intern();//由于常量池中没有"good",于是将 s6 实例的引用添加到常量池中,返回此引用赋给s7
String s8 = "good";//常量池中已有值为"good"的实例(引用),也就是指向s6实例的引用,不会创建"good"了,因为常量池的字符串都是唯一的。返回 s6 实例的引用赋给s8。
System.out.println(s6 == s7);//s6与s7指向的是同一个实例:true
System.out.println(s7 == s8);//true
System.out.println(s6 == s8);//true
参考资料
(1条消息) Java字符串字面量是何时进入到字符串常量池中的_TomAndersen的博客-CSDN博客
1.1.15 常用类 - 小陈学java编程 - 博客园 (cnblogs.com)