String.intern()方法

  • 在JDK1.7之前,常量池是通过永久代实现的,当出现字符串字面量或者调用String.intern()方法时,此字符串没有在常量池中存在,则会将此字符串复制到常量池中,intern方法返回的是在永久代中的引用。

如代码:

String str1 = new StringBuilder().append("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder().append("ja").append("va");
System.out.println(str2.intern() == str2);

str1指向的是堆中的对象,str1.intern()方法会把str1中的字符串复制到常量池中,并返回常量池中的引用,所以“str1.intern() == str1”为false;

str2同理,str2指向堆中的引用,str2.intern()指向永久代中的引用,所以“str2.intern() == str2”为false;


  • 在JDK1.7之后,常量池不再通过永久代实现了,而是放在了Native内存中,并且不会将未出现过的字符串复制到常量池中,而是复制其在堆中的引用到常量池中。

在JDK1.7之后的环境下执行上述代码,str1.intern()会将str的引用复制到常量池中,所以“str1.intern() == str”为true;

而“str2.intern() == str2”为false,因为java是在虚拟机启动时就被加入到常量池的,那么str2.intern()就会返回常量池中已经存在的引用。

再看另一段代码:

String s1 = new StringBuilder().append("计算机").append("软件").toString(); 
String s2 = "计算机软件";
System.out.println(s1 == s2); 
System.out.println(s1.intern() == s1);
System.out.println(s1.intern() == s2);

只看它在jdk1.7之后的情况。

s1是指向堆中的引用,s2也是指向堆中的引用,但是s2的字符串是首次出现,所以会将s2在堆上的引用复制到常量池,那么,“s1 == s2”肯定是false,二者指向不同的对象;“s1.intern() == s1”同样为false,因为s1.intern()调用时,常量池中已经有了该字符串(s2),返回的是堆中的s2,那么,“s1.intern() == s2”为true。

如果代码顺序变成下面这样呢:

String s1 = new StringBuilder().append("计算机").append("软件").toString(); 
System.out.println(s1.intern() == s1);
String s2 = "计算机软件";
System.out.println(s1 == s2); 
System.out.println(s1.intern() == s2);

会输出三个true。因为在执行“s1.intern() == s1”的时候,常量池中还没有此字符串,所以将s1的引用复制到常量池,之后的s2和s1.intern()都是返回的此引用,也就是堆上的同一个实例。

如有指教,请告知!

JVM