Java中String的instern方法和jvm常量池若干问题分析
Feb222018
1 在oracle的Hotspot虚拟机中,以下代码,如果把
str1.intern();
String str2 = “11”;
这两行代码交换位置,那么在JDK1.7及以后的JVM版本中,执行的结果是不同的。
原因分析,见代码注释。
package test.oom; public class TestIntern2 { public static void main(String[] args) { String str1 = new StringBuilder("1").append("1").toString(); /** * * intern 方法会检查常量池里面是否已经存在相同的常量,如果存在,则返回这个常量引用, * 如果不存在,则 * 1) JDK1.6 中, 调用intern 方法会复制一份字符串放到常量池中,此时会有两份 字符串,堆上一份,常量池里一份 * 2) 而JDK1.7 以后,不会复制,仅仅会在常量池中创建一个引用,该引用指向堆上的原始 字符串 * * 1) 在JDK1.6 中, * case 1: * str1.intern(); //先执行 * String str2 = "11"; * 常量池里面没有 "11" ,会创建一个字符串常量"11",放到常量池里,这个常量和str1是不同的 * 而str2是指向常量池中的字符串的,所以str1 和 str2 是不同的 * * case 2: * String str2 = "11"; //先执行 * str1.intern(); * 先执行 String str2 = "11"; 会把11放到常量池,然后返回, 在调用str1.intern 发现常量池里面已经有11,然后返回常量池引用 * 常量池里的11和str1的11时不同的,所以 str1 != str2 * * 2) 在JDK1.7中, * case 1: * str1.intern(); //先执行 * String str2 = "11"; * 常量池里面没有 "11", 会常见一个常量,指向str1, 然后str2=“11” 时发现,常量池里已经有11了,于是返回常量池引用,而该引用是指向str1的 * 所以,此时str1 == str2 * * case 2: * String str2 = "11"; //先执行 * str1.intern(); * 先执行 String str2 = "11";会在堆上分配一个对象11, ,然后再常量池中创建一个常量,指向 这个新的11,跟str1是不同的 * 然后执行 str1.intern(),发现已经存在常量11了,于是返回常量的引用,指向上述新建的11, * 所以,此时 str1 != str2 */ str1.intern(); String str2 = "11"; System.out.println("str1 == str2 " + (str1 == str2)); } }
2 同样,在oracle的Hotspot虚拟机JDK1.7及以后版本中,会有下面一个诡异的问题
package test.oom; public class TestIntern { public static void main(String[] args) { /** * 在Hotspot JVM 1.7 及以后的版本中, * 下面的代码, str1和str2 仅仅相差了一个字符,str1是java1 而 str2 是java * 然而,执行的结果却截然不同, * str1.intern() == str1 true * str2.intern() == str2 false * * 分析原因,只能是常量池中默认就已经有了关键字 java 字符了, 而 str2 是堆上新建的一个字符对象,而 * str2.intern() 返回的是常量池中的引用,所以 * str2.intern() 1= str2 * 周志明 著 《深入Java虚拟机》 第二版 57页中说, 是因为 "java" 这个字符串在执行StringBuilder.toString() * 之前已经出现过,字符串常量池中已经有它的引用了。 然而, 并没有搞明白为啥。 */ String str1 = new StringBuilder("ja").append("va1").toString(); System.out.println("str1.intern() == str1 " + (str1.intern() == str1)); String str2 = new StringBuilder("ja").append("va").toString(); System.out.println("str2.intern() == str2 " + (str2.intern() == str2)); } }
赞 赏
微信赞赏 支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/java-core/2667.html | 边城网事