这个intern()方法简直是让人抓狂,搞了一天终于搞明白了(`・ω・´),简直爆炸。
这个方法在JDK 1.7做出了重大改变,先说一下在JDK 1.7以后版本里的情况。
在JDK 1.7中,intern()方法不会再复制实例,只是会把首次遇到的字符串实例的引用添加到常量池中(没有复制),并返回此引用。看如下示例:
public class Ex{
public static void main(String[] args){
// String st="javac";
String s1="jav";
s1=s1+"ac";//相当于是new了一个字符串对象"javac",放入到堆内存中。
//s1="jav"+"ac"是等价于s1="javac"的,并没有在堆内存中new一个对象。
System.out.println(s1.intern()==s1);
String s2="ja";
s2=s2+"va";
System.out.println(s2.intern()==s2);
String s3=new String("abc");
System.out.println(s3.intern()==s3);
}
}运行结果:

s1是堆内存中字符串实例"javac"的引用,intern()方法会把此引用放到字符串常量池中,并返回这个引用,因此intern()返回的引用和s1这个引用是同一个。
按照同样的道理,第二个也应该是true啊,一直被这个示例搞晕了,后来去查了些资料,貌似是JVM在执行main方法之前会进行一系列的复杂操作,会把这个java当做一个字符串常量扔到常量池里面,所以常量池里面有这个字符串常量了,因此intern()返回的是常量池的引用,而s2这个是堆中的引用,所以是false。
第三个呢,在执行new String("abc")的时候,JVM会先把"abc"放到常量池中,然后才在堆中创建一个"abc"的实例,s3是指向堆内存的引用,intern()方法返回的是常量池的引用,所以是false。
如果我们把第一行的注释去掉,那么第一个打印的也会是false,因为javac会被先一步放入到常量池中。
下面说一下在JDK 1.6中的情况,在JDK 1.6中 intern() 方法会把首次遇到的字符串实例复制到常量池中,并返回此引用。所以针对上面的例子,打印出来的全是false,因为intern()返回的全是指向常量池的引用,而s1,s2,s3全是堆中对象的引用。
补充(JDK 1.8):
public class Ex1{
public static void main(String[] args){
String s1="jav";
s1=s1+"ac";
// String s3=s1.intern(); //语句1
String s2="javac";
String s3=s1.intern();
System.out.println(s1==s2);
System.out.println(s2==s3);
}
}输出结果:

s1是堆中的引用,在s1调用intern()方法之前执行了s2,所以会把"javac"字符串放到常量池中,所以s2是指向常量池的引用,这个时候再调用intern()方法就会返回常量池的引用,所以s3也是指向常量池的引用,所以第二个是true,第一个是false。如果把s3放到语句1的位置,则两个都是返回true。
本文详细解析了Java中intern()方法的工作原理及其在不同JDK版本中的行为变化。通过具体示例说明了该方法如何处理字符串常量池中的引用,并对比了JDK1.6与1.7之后版本的区别。
1552

被折叠的 条评论
为什么被折叠?



