真正理解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
}