参考连接:https://www.jianshu.com/p/be66e22f5fc8 可以联系我删除本博客
我们知道再jvm的运行时内存可以分为堆、方法区、程序计数器、虚拟机栈和本地方法栈。而在方法区中有一个字符串常量池,用来保存字符串这个不可变量。如果我们使用String str=new String("java虚拟机")来new一个string对象,则该对象的实例保存在堆中。如果我们使用String str="java虚拟机"来创建一个字符串,jvm首先会在字符串常量池中创建该String的实例,然后将常量池中该实例的引用返回给str。
new出来的String保存在堆中,如果我们想让字符串常量池中也保存该string的实例呢?可以使用String.intern()这个方法将字符串复制到常量池中,返回在常量池中的引用。
但是在jdk1.7以后,使用String.intern()方法和之前有一些不同。intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。
当然这个时候,常量池被从方法区中移出来到了堆中。
我们看一下如下的代码
public static void main(String[] args) { String str1=new StringBuilder("java").append("虚拟机").toString();//执行完这行代码后,常量池中会有"java"和"虚拟机",但是不会有"java虚拟机"。 System.out.println(str1.intern()==str1); String str2=new String("我喜欢java"); //执行完这行代码后,常量池中会有"我喜欢java" System.out.println(str2==str2.intern());
true
false
分析
str1指向的实例是在堆中,是由“java”和"虚拟机"拼接成的。执行完第一句代码后,执行完这句话后,常量池中会有"java"和"虚拟机",但是不会有"java虚拟机"。然后使用str1.intern()会在常量池中保存str1实例的引用,并且返回引用,因此str1.intern()==str1。
而执行完String str2=new String("我喜欢java");后,常量池中会有"我喜欢java",所以在使用str2.intern()返回的就是字符串常量池中的引用,而str2指向的是堆中的引用,因此str2!=str2.intern()。