美团技术文章-深入解析String#intern
作用
在jdk1.6及之前,使用intern()方法,判断字符串常量池是否存在指定的字符串,如果存在,就返回字符串常量对象的引用,如果不存在,就将堆中的字符串复制到字符串常量池中
在jdk1.7及之后,使用intern()方法,判断字符串常量池是否存在指定的字符串,如果存在,就返回字符串常量对象的引用,如果不存在,就将堆中对象的引用复制到字符串常量池中
好处
就是能够防止我们在创建字符串对象的时候在字符串缓冲池中创建太多的字符串,导致内存爆满,出现oom错误
对不同的jdk版本的intern()方法作用都是不一样的,就是因为不同jdk版本的字符串常量池在jvm中存储的位置不同
示例
代码一
JDK6/7/8返回的都是false
// 常量池中创建"1",堆中创建"1"
String s1 = new String("1");
// 常量池中已有"1",所以jdk6和jkd7都是返回指向常量池"1"的引用
// 但因为该语句没有赋值操作,所以s1仍指向堆中"1"
s1.intern();
// s2指向常量池中已存在的"1"
String s2 = "1";
// s1指向堆中"1",s2指向常量池中"1",false
System.out.println(s1==s2);
因为常量池里面有"1",所以jdk6和jkd7都是返回指向常量池"1"的引用,又因为s1.intern()有赋值一个新的字符串,所以s3是指向字符串常量池对象的引用,则jdk6/7/8都是显示以下答案
// 常量池中创建"1",堆中创建"1"
String s1 = new String("1");
// 常量池中已有"1",所以jdk6和jkd7都是返回指向常量池"1"的引用
// 但因为该语句没有赋值操作,所以s1仍指向堆中"1"
String s3 = s1.intern();
// s2指向常量池中已存在的"1"
String s2 = "1";
// s1指向堆中"1",s2指向常量池中"1"
System.out.println(s1==s2);// false
System.out.println(s2==s3);// false
System.out.println(s1==s3);// true
代码二
// 常量池生成一个"1",堆生成一个"11"
// s3指向堆中"11"
// 中间还有2个匿名的new String("1")暂不讨论
String s1 = new String("1") + new String("1");
//因为常量池中不存在"11",
//jdk6会将堆中"11"复制到常量池中,
//jdk7则将堆中"11"的引用添加到常量池中,
//此时s3仍指向堆中"11"
s1.intern();
//因为常量池中已存在"11"或其引用,s4指向常量池中"11"
String s2 = "11";
//jdk6中,s4指向常量池中"11",s3指向堆中"11",false
//jdk7中,s4指向常量池中指向堆中"11"的引用,true
System.out.println(s1==s2);
在JDK6中,s4指向常量池中"11",s3指向堆中"11"
在JDK7及以上,s4指向常量池中指向堆中"11"的引用