字符串的intern()方法--字符串常量池

  这个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。

猜你喜欢

转载自blog.csdn.net/karute/article/details/80186413
今日推荐