真正理解String#intern
intern作用
intern用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。
如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。
案例分析
请先看字符串常量池,不然真的理解不透彻
jdk1.8测试:
案例一:
public static void main(String[] args) {
//先在常量池放入1,再在堆上生成String obj,obj的char[] value指向常量池的1,栈上s1指向String obj
String s1 = new String("1");
//1已经在常量池了,所以这行代码没有任何意义
s1.intern();
//栈s2指向常量池的1
String s2 = "1";
//s1指向String obj, s2指向常量池,肯定不相等
System.out.println(s1 == s2);//flase
//用StringBuilder append 1和2,会把1和2放入到常量池中,堆中生成一个StringObj, obj的char[]value=12
//注意此时常量池没有12,value不是指向常量池了,而是把12存在自己的内存中,栈s3指向obj
String s3 = new String("1") + new String("2");
//此时常量池没有12,他会把12的引用即String obj的引用放到常量池中(1.7以前是直接放12到常量池)
s3.intern();
//常量池有指向12的引用,把这个引用(即obj的地址)给s4
String s4 = "12";
//s3和s4都指向obj,所以相等
System.out.println(s3 == s4);//true
}
案例二:
public static void main(String[] args) {
String s1 = "hello";//栈s1指向常量池hello
String s2 = " world";//栈s2指向常量池 world
String s3 = s1+s2;//StringBuilder append hello和world,s3指向堆的obj,obj的char[]value存hello world
//此时常量池没有hello world,把s3的引用存入常量池
s3.intern();//这行代码如果移下一行结果就变了
//s4指向常量池s3的地址
String s4 = "hello world";
System.out.println(s4 == s3);//true
}
试着自己画一下图吧
案例三:
public static void main(String[] args) {
//toString里面new String(char []value)
//往常量池添加计算机,软件这两个字符串
//堆中String obj的char[]value保存计算机软件这个字符串,str1指向堆中obj
String str1 = new StringBuilder("计算机").append("软件").toString();
//因为此时常量池没有计算机软件,str1.intern()会把str1的引用添加到常量池并返回str1的引用,所以相等
System.out.println(str1.intern()==str1);//输出true
//往常量池添加ja,va这两个字符串
//因为常量池已经有java这个字符串了,堆中String obj的char[]value指向常量池的java,str2指向obj
String str2 = new StringBuilder("ja").append("va").toString();
//str2.intern()返回java,而str2指向堆obj,地址不相等
System.out.println(str2.intern() == str2);//输出false
}
案例四:
public static void main(String[] args) {
String str1 = "a";//str1指向常量池a
String str2 = "b";//str2指向常量池b
String str3 = "ab";//str3指向常量池ab
String str4 = str1 + str2;//str4指向堆String obj,obj的char[] value指向常量池ab
String str5 = new String("ab");//str5指向堆String obj, obj的char[] value指向常量池ab
System.out.println(str5 == str3);//f
System.out.println(str5.intern() == str3);//t
System.out.println(str5.intern() == str4);//f
String a = new String("ab");//a指向堆String obj, obj的char[] value指向常量池ab
String b = new String("ab");//b指向堆String obj, obj的char[] value指向常量池ab
String c = "ab";//c指向常量池ab
String d = "a" + "b";//d指向常量池ab (编译期确定)
String e = "b";//e指向常量池b
String f = "a" + e;//f指向堆String obj,obj的char[] value指向常量池ab (StringBuilder实现)
System.out.println(b.intern() == a);//f
System.out.println(b.intern() == c);//t
System.out.println(b.intern() == d);//t
System.out.println(b.intern() == f);//f
System.out.println(b.intern() == a.intern());//t
}