请先查看一下代码,不妨猜测一下,结果会如何。
/**
* @ClassName: StringInternDemo.java
* @Description: TODO
* @author: mazhuo
* @version: V1.0
* @Date: 2019年11月6日 下午1:23:09
*/
public class StringInternDemo {
/**
* @Title: main
* @Description: TODO
* @param @param args 设定文件
* @return void 返回类型
* @throws
*/
public static void main(String[] args) {
String s = new String("11");
s.intern();
String s2 = "11";
System.out.println(s == s2);
String s3 = new String("3") + new String("4");
s3.intern();
String s4 = "3" + "4";
System.out.println(s3 == s4);
}
}
当程序执行在jdk1.6的时候:结果为false,false;当程序执行在jdk1.7和我jdk1.8的时候:结果为false和,true。要想搞清楚这个问题,首先我们需要清除一下几个问题:
1、在jdk1.6之前的版本中:字符串常量池是放在堆中的Perm区的。 在jdk1.7之后的版本中:字符串常量池已挪进堆中的正常区域了。
2、String s = new String("1")在系统中究竟创建了多少对象
首先有一点可以确认,一定在java堆中创建了String的对象。如果在常量池中不存在1,那么也会在常量池中新建一个字符串1,如果已经存在就不需要创建了。
3、intern()方法是检查在常量池中是否存才该字符串,如果不存在,则将当前字符串放入常量池中;如果存在则不需要做任何操作。
在jdk1.6之前,由于堆空间和常量池是分开的,所以放入的意思是将字符串的值复制一份放进常量池中。
在jdk1.7之后,由于堆空间和常量池在一起,所以放入的意思是将字符串的引用地址放进常量池中。
4、= 比较的是两个字符串指向的是否是同一个对象。
那么,现在上述问题就已经很好理解了(以下仅仅解释下1.7的结果,1.6的结果已经显而易见了)
在这段代码中,首先在堆中创建了string对象,然后在常量池中创建了“11”字符串。所以s2直接指向的是常量池中的“11”,而s指向的是堆空间的对象。因而第一个结果为false。
在这段代码中,第一行的代码在堆中创建了string对象以及在常量池中的“3”和“4”。第二行intern函数检查常量池中是否有“34”,没有就将s3的引用地址放入到常量池中,这样s4就直接指向常量池中的“34”也就是s3的引用地址,这样,s3和s4指向的就是同一个地址了,所以最终的结果为true。