Java7之后的intern
最近在《深入理解Java虚拟机》一书中了解到,以下内容在Java7中第一个返回true,第二个返回false,产生了一些疑惑,经过一番搜索,对intern的理解有所加深,这里记一下。
public class RuntimeConstantPoolOOM { public static void main(String[] args) { String str1 = new StringBuilder("计算机").append("软件").toString(); System.out.println(str1.intern() == str1); String str2 = new StringBuilder("ja").append("va").toString(); System.out.println(str2.intern() == str2); } }
很久前就知道intern会在常量池中创建常量,但是第一个为什么是true?
回过头来再去了解intern,原来在java7之后,intern方法在第一次将字符串加入常量池的时候,是以当前对象作为常量放进的常量池的。
因此,str1的intern被调用的时候,str1本身已经被放进了常量池,因此第一个是true
对于java6(书中原文):
这段代码在JDK 6中运行,会得到两个false,而在JDK 7中运行,会得到一个true和一个false。产生差异的原因是,在JDK 6中,intern()方法会把首次遇到的字符串实例复制到永久代的字符串常量池中存储,返回的也是永久代里面这个字符串实例的引用,而由StringBuilder创建的字符串对象实例在Java堆上,所以必然不可能是同一个引用,结果将返回false。
对于java7(书中原文):
而JDK 7(以及部分其他虚拟机,例如JRockit)的intern()方法实现就不需要再拷贝字符串的实例到永久代了,既然字符串常量池已经移到Java堆中,那只需要在常量池里记录一下首次出现的实例引用即可,因此intern()返回的引用和由StringBuilder创建的那个字符串实例就是同一个。
第二个是因为java这个字符串在java7中其它地方出现过,不满足第一次出现的条件。
参考:
https://www.zhihu.com/question/51102308
https://blog.csdn.net/weixin_44201525/article/details/120897052
书中前边只看到一个Java虚机规范的内存图,没有对几个java版本实际的存储位置区分的图(虽然也有文字描述),看到一个图不错,正好补了这个漏,学习一下:
转自:https://www.csdn.net/tags/OtTaYgxsMDg0NDktYmxvZwO0O0OO0O0O.html