最近在回头看java基础这块,遇到一段比较有意思的代码
@Test
public void testIntern(){
String s1 = new String("helloworld"); // 堆
String s2 = "helloworld"; //堆中的字符串常量池中
String intern1 = s1.intern(); //internl引用s1的堆对象
System.out.println(s1 == s2); //false
String s3 = new String("helloyeah"); //堆 与 字符串常量池 S3是堆的引用
String intern3 = s3.intern(); //intern3是字符串常量池中引用s3的堆对象
String s4 = "helloyeah"; //字符串常量池里已经有了 helloyeah,所以直接返回这个引用
System.out.println(s3 == s4); //false
System.out.println(intern3 == s4); //true 二者引用的同一个常量
String s5=new String("hello")+new String("yeah"); //堆
System.out.println(s5==s3); //false
String intern5=s5.intern(); // 去常量去查是否有"helloyeah"常量池,发现已经有了s3.intern()的的这个。
System.out.println(intern5==intern3); //true 因为引用相同
System.out.println(intern5==s4); //true 因为引用相同
String s6="helloyeah"; //字符串常量池
System.out.println(s5==s6); //false
String s7=new String("hello")+new String("yeah0"); //堆
String intern7=s7.intern(); //intern7是字符串常量池中引用s7的堆对象
String s8="helloyeah0"; //判断常量池中是否有这个字面量是否已经存在引用,发现s7已经有了,则返回intern7
System.out.println(s7==s8);//true
System.out.println(intern7==s8);//true
}
这段代码是来自一篇博文的评论区,本来看完这篇文章,跑了跑代码,感觉没有啥问题,但是看到评论区的时候,发现自己对这块理解的还是有问题。大家可以先想一下上面代码每一次的结果是什么?
https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html这篇文章里说的比较清楚,好好看看
主要就是java7之后,由于字符串常量池从原来的perm space挪到了 heap 区,对intern方法的改变。最大的区别就是java7之后,intern操作后,建立的是一个一个引用,如果字面量字符串存在,则直接引用,如果不存在,则引用的是堆里的对象。
2019-07-13
今天阅读 深入java虚拟机 里提到了这块常量池,文中给出了一个有趣的例子,以及一个简单的判断的方法
1 @Test 2 public void testConstantPoolOOM(){ 3 String str2=new StringBuilder("ja").append("va").toString(); 4 System.out.println(str2.intern()==str2); 5 String str3=new StringBuilder("ja1").append("va").toString(); 6 System.out.println(str3.intern()==str3); 7 String str4=new StringBuilder("jav").append("a").toString(); 8 System.out.println(str4.intern()==str4); 9 System.out.println(str2==str4); 10 System.out.println(str4.intern()==str2.intern()); 11 String str1=new StringBuilder("计算机").append("234").toString(); 12 System.out.println(str1.intern()==str1); 13 }
有趣,是"java"这个字符串为什么会提前在常量池里存在了,简单的判断方法就是判断,常量池里是否首次出现这个字符串,如果是首次,则建立一个引用关系,如果不是首次,则会返回之前引用的引用。