以下測試結果都是在HotSpot JDK1.7中運行的
源碼:
public class Intern{ public static void main(String[] args){ String str1 = new StringBuilder("計算機").append("系統").toString(); System.out.println(str1.intern() == str1); String str2 = new StringBuilder("In").append("tern").toString(); System.out.println(str2.intern() == str2); String str4 = new StringBuilder("ja").append("va").toString(); System.out.println(str4.intern() == str4); String str3 = new StringBuilder("計算機").append("系統").toString(); System.out.println(str3.intern() == str3); System.out.println(str1.intern() == str3.intern()); } }
運行結果:
true false false false true
分析:
1. JDK1.7中,HotSpot已經開始逐步“去永久化”,也就是說對於jvm內存分布中的方法區(即我們常說的常量區)里邊的類,對象常量等信息,已經並不一定是永久存在的了,也可能會被GC回收掉
2. JDK1.7中,對String的intern方法做了修改,在1.6及以前的JDK中,intern方法會在調用時先去常量池中查看是否有相同的字符串(equals()),如果有那就返回常量的引用,如果沒有就復制字符串實例放到常量區,然后再返回對常量的引用,所以如果用JDK1.6 及以前的版本運行上邊代碼的話,輸出結果都是false。JDK1.7中,intern方法不會再復制實例,而是在常量池中記錄首次出現的字符串(equals())的實例引用。在上邊的例子中,調用str1.intern()方法時,由於計算機系統String對象是首次出現,此時就會把此對象實例的引用放到常量池中,返回的也是常量池中對首次出現的實例的引用,所以是true。對於Intern和java,由於並不是第一次出現(在加載class文件和執行java命令時已經存儲到常量池里),所以輸出是false,對於第二次出現的計算機系統,由於不是首次出現,所以是false
3. 對於str1.intern() == str3.intern() 由於返回的都是對首次創建計算機系統字符串實例的引用,所以是true
總結:
1. 1.7JDK中intern()方法始終返回的也是常量池的引用信息,只不過不同的是1.7中返回的是相同字符串(equals())首次創建時的引用地址
2. 常量池中不直接存儲字符串常量,而存儲的是首次創建此字符串時的引用