当前位置: 首页 > Java Core > 正文

Java中String的instern方法和jvm常量池若干问题分析

目 录
 [ 隐藏 ]

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 | 边城网事

该日志由 边城网事 于2018年02月22日发表在 Java Core 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: Java中String的instern方法和jvm常量池若干问题分析 | 边城网事

Java中String的instern方法和jvm常量池若干问题分析 暂无评论

发表评论

快捷键:Ctrl+Enter