對String Intern()方法的理解

今天重新看了一點周志明大佬的《深入理解Java虛擬機》,發現這個地方講的不是很透徹,在網絡上看到一些博客基本也都是在搬運原文,搞得一頭霧水。弄了半天算是徹底明白了,做一下筆記。

搬運一下原文對intern()方法的說明:String::intern()是一個本地方法,它的作用是如果字符串常量池中已經包含一個等於此String對象的字符串,則返回代表池中這個字符串的String對象的引用(指的是常量池中的實例);否則,會將此String對象包含的字符串添加到常量池中,並且返回此String對象的引用(指的是堆中的實例)。括號中是我的個人理解,由於作者兩種情況說的結果都是”String對象的引用”,讓我錯誤地理解為都是堆中實例的引用。接下來我們看幾段代碼。

String a = "a";
String b = new String("a");
System.out.println(a == b);

上面這段代碼結果顯然是false,雖然兩者值相等,但是a是字面量(常量池中),b在堆中(因為b是通過new創建)。

接下來我們看書中的這個例子:

String str1 = new StringBuilder("計算機").append("軟件").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);

結果是true,false。解釋如下:”計算機軟件”從未出現在常量池,因此str1.intern()的結果為堆中的值為”計算機軟件”的String對象,同時也會將”計算機軟件”這個字符串加入到常量池中;”java”曾出現在sun.misc.Version這個類中,因此早就存在於常量池裡,所以str2.intern()的結果為常量池中的值為”java”的字面量。

再看看以下代碼段:

String str1 = new StringBuilder("計算機").append("軟件").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder("計算機").append("軟件").toString();
System.out.println(str2.intern() == str2);

結果是true,false。這說明第一個intern()將”計算機軟件”這個字符串加入到了常量池中,導致str2.intern()實際上是在常量池中,而str2在堆中。

String str1 = new String("計算機軟件");
System.out.println(str1.intern() == str1);

這個結果是false,因為這樣的構建String的方法會做兩件事:在常量池中創建一個實例,再複製到堆中創建一個對象。這就導致str1.intern()實是在常量池中,而str1在堆中。

String str1 = new String("計算機軟件");
System.out.println(str1.intern() == "計算機軟件");

而這個結果是true,就很好理解了。