對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,就很好理解了。

Tags: