String.intern()详解,关于String s2 = newString("ja") + new String("va"); s2.intern();
写这篇文章的情况是在看面试题的时候遇到了一些疑问,查看了好多大神的文章,总算有了一些理解,为了记忆,整理了一下。
首先看一下面试题
public static void m1(){
String s1 = new StringBuilder("go").append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja").append("va").toString();
System.out.println(s2.intern() == s2);
}
public static void main(String[] args) {
m1();
}
输出结果:
true
false
当时直接懵逼了,为什么同样的方式,结果为什么不一样。测试发现问题出在java这个字符串上。
百度,学习了https://www.zhihu.com/question/51102308中的一些知识,发现原来是在JVM启动的时候调用了一些方法,在常量池中已经生成了"java"字符串常量,所以才会有所不同。
到这里我还是迷迷糊糊的,这和字符串常量啥关系呀。急的我是抓耳挠腮,继续百度,发现了一个大神,SEU_Calvin的一篇博客,http://blog.csdn.net/seu_calvin/article/details/52291082。
我把这道面试题给改了一下:
public static void main(String[] args) {
m6();
}
public static void m6(){
String s1 = new String("go") + new String("od");
s1.intern();
String s3 = "good";
System.out.println(s1 == s3);
String s2 = new String("ja") + new String("va");
s2.intern();
String s4 = "java";
System.out.println(s2 == s4);
}
输出结果:
true
false
继续测试
public static void main(String[] args) {
m6();
}
public static void m6(){
String s1 = new String("good");
s1.intern();
String s3 = "good";
System.out.println(s1 == s3);
}
发现结果成:false
问题出在哪呢,虽然看了大神的博客,但是还是有一些疑问。我又 参考了自己之前写的一篇博客。我先把大神的图拿过来
看了有些不明白,为了图省事我手动修改了一下
为什么这么改呢,先看下面大神给出的过程。
String s = newString("1"),生成了常量池中的“1”和堆空间中的字符串对象。
s.intern(),这一行的作用是s对象去常量池中寻找后发现"1"已经存在于常量池中了。
String s2 = "1",这行代码是生成一个s2的引用指向常量池中的“1”对象。
结果就是 s 和 s2 的引用地址明显不同。因此返回了false。
String s3 = new String("1")+ newString("1"),这行代码在字符串常量池中生成“1”,并在堆空间中生成s3引用指向的对象(内容为"11")。注意此时常量池中是没有 “11”对象的。
s3.intern(),这一行代码,是将 s3中的“11”字符串放入 String常量池中,此时常量池中不存在“11”字符串,JDK1.6的做法是直接在常量池中生成一个 "11" 的对象。
但是在JDK1.7中,常量池中不需要再存储一份对象了,可以直接存储堆中的引用。这份引用直接指向s3引用的对象,也就是说s3.intern() ==s3会返回true。
String s4 = "11", 这一行代码会直接去常量池中创建,但是发现已经有这个对象了,此时也就是指向s3引用对象的一个引用。因此s3 == s4返回了true。
重点在
到这里,我总算弄明白了,当浮一大白!