理解String类的intern()方法

测试环境:eclipse+JDK 1.8

测试例子:

public static void main(String[] args){
    String s1=new String("a")+new String("b"); //1
    System.out.println(s1.intern()==s1); //2

    String s2=new String("a")+new String("b"); //3
    System.out.println(s2.intern()==s2); //4
}

JDK 1.6 输出结果

false
false

JDK 1.7(1.8) 输出结果

true
false

引自周志明《深》解释:

在JDK 1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用;而JDK 1.7(以及部分虚拟机)的intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用。

两个图帮助理解:

JDK 1.6

  • 执行第一句后,字符串常量池将会产生字符串“a”和“b”以及它们的引用。在堆区创建一个String对象,并将引用返回给s1。
  • 执行第二句s1.intern()方法后,在JDK 1.6中,先将字符串“ab”复制到字符串常量池,然后创建字符串“ab”的引用并返回给si.intern()。此时,明显s1和s1.intern()指向的对象不同,返回false。
  • 第三和第四句类似,值得注意的是,此时如果执行s1.intern()==s2.intern()将会返回true。

JDK 1.7(1.8)

注意1.7之后,字符串常量池迁移到堆区。

  • 执行第一句,与JDK 1.6相同
  • 执行第二句s1.intern()方法时,发现字符串常量池中并没有字符串“ab”的引用,此时不再在字符串常量池中创建“ab”字符串,而是在字符串常量池中创建“ab”字符串的引用,然后指向首次出现的实例对象,也即是s1所指向的对象,所以s1.intern()==s1返回true。
  • 执行第四句s2.intern()方法时,发现字符串常量池中已经存在字符串“ab”的引用,直接指向该引用。此时如果执行s2.intern()==s1.intern()或者s2.intern()==s1都会返回true。

为了验证以上所述,再进行一次检验(JDK 1.8)

public static void main(String[] args){
    String s1=new String("a")+new String("b"); //1
    System.out.println(s1.intern()==s1); //2
    s1=null;
    System.gc();
    String s2=new String("a")+new String("b"); //5
    System.out.println(s2.intern()==s2); //6
}

运行结果

true
true

调用gc()方法,将s1指向的实例对象清除,所以执行到第6句时,字符串常量池中不存在“ab”字符串引用,之后的操作与执行1、2句相同。

猜你喜欢

转载自blog.csdn.net/GD_Hacker/article/details/80541782