《深入理解java虛擬機器》String.intern()探究

來源:互聯網
上載者:User

標籤:.net   sys   const   運行   對象   ons   als   java   並且   

public class RuntimeConstantPoolOOM {    public static void main(String[] args) {        String str1 = new StringBuilder("電腦").append("軟體").toString();       // String str3= new StringBuilder("電腦軟體").toString();        System.out.println(str1.intern() == str1);        String str2 = new StringBuilder("Java(TM) SE ").append("Runtime Environment").toString();        System.out.println(str2.intern() == str2);    }

書中寫道,如果JDK1.6會返回兩個false,JDK1.7運行則會返回一個true一個false。

因為JDK1.6中,intern()方法會把首次遇到的字串執行個體複製到永久代中,返回的也是永久代中這個字串的執行個體的引用,而StringBulder建立的字串執行個體在Java堆上,所以必然不是同一個引用,將返回false。

在JDK1.7中,intern()的實現不會在複製執行個體,只是在常量池中記錄首次出現的執行個體引用,因此返回的是引用和由StringBuilder.toString()建立的那個字串執行個體是同一個。

str2的比較返回false因為"java"這個字串在執行StringBuilder.toString()之前已經出現過,字串常量池中已經有它的引用了,不符合“首次出現”的原則,而“電腦軟體”這個字串是首次出現,因此返回true。

一、

那麼就有疑問了,這個“java”字串在哪裡出現過呢?顯然並不是直接出現在這個類裡面。

我們分別開啟String 、StringBuilder和System類的源碼看看有啥發現,

其中在System類裡發現      參考72753494

二、

這個問題解決了,然後我又發現了另外一個問題。除了這些在虛擬機器載入時就初始化的常量,定義其他的字串常量,比如“nihao”.

先運行這個代碼String str3 = new StringBuilder("ni").append("hao").toString();System.out.println(str3==str3.intern());通過上面的解釋,運行結果為true.在運行這個代碼String str3 = new StringBuilder("nihao").toString();System.out.println(str3==str3.intern());其結果是什嗎?應該還是true吧,畢竟通過上一個運行結果可以知道"nihao"這個字串常量沒有被積極式載入到常量池中。但是運行結果卻是false.

StringBuilder的append方法沒有改變字串的引用地址,只是把其值改變了,為什麼加了append返回的是true,沒有加append卻是false呢?如果在後面多加幾個append返回的也是true。

解決:

先運行這個代碼
String str3 = new StringBuilder("ni").append("hao").toString();
System.out.println(str3==str3.intern());
上面的代碼等價於下面的代碼
String a = "ni";
String b = "hao";
String str3 = new StringBuilder(a).append(b).toString();
System.out.println(str3==str3.intern());
很容易分析出:
“nihao” 最先建立在堆中 str3.intern()然後緩衝在字串常連池中 運行結果為true.

lz代碼
String str3 = new StringBuilder("nihao").toString();
System.out.println(str3==str3.intern());
可以寫成下面的形式
String a = "nihao";
String str3 = new StringBuilder(a).toString();
System.out.println(str3==str3.intern());

很容易分析出:
“nihao” 最先建立在常量池中, 運行結果為false.

 

三、關於java intern的一些深入理解

儘管在輸出中調用intern方法並沒有什麼效果,但是實際上後台這個方法會做一系列的動作和操作。在調用”ab”.intern()方法的時候會返回”ab”,但是這個方法會首先檢查字串池中是否有”ab”這個字串,如果存在則返回這個字串的引用,否則就將這個字串添加到字串池中,然會返回這個字串的引用。

可以看下面一個範例:

String str1 = "a";String str2 = "b";String str3 = "ab";String str4 = str1 + str2;String str5 = new String("ab"); System.out.println(str5.equals(str3));System.out.println(str5 == str3);System.out.println(str5.intern() == str3);System.out.println(str5.intern() == str4);

得到的結果:

truefalsetruefalse

為什麼會得到這樣的一個結果呢?我們一步一步的分析。

  •  第一、str5.equals(str3)這個結果為true,不用太多的解釋,因為字串的值的內容相同。
  •  第二、str5 == str3對比的是引用的地址是否相同,由於str5採用new String方式定義的,所以地址引用一定不相等。所以結果為false。
  •  第三、當str5調用intern的時候,會檢查字串池中是否含有該字串。由於之前定義的str3已經進入字串池中,所以會得到相同的引用。
  •  第四,當str4 = str1 + str2後,str4的值也為”ab”,但是為什麼這個結果會是false呢?先看下面代碼:
String a = new String("ab");String b = new String("ab");String c = "ab";String d = "a" + "b";String e = "b";String f = "a" + e;System.out.println(b.intern() == a);System.out.println(b.intern() == c);System.out.println(b.intern() == d);System.out.println(b.intern() == f);System.out.println(b.intern() == a.intern());

運行結果:

falsetruetruefalsetrue

由運行結果可以看出來,b.intern() == a和b.intern() == c可知,採用new 建立的字串對象不進入字串池,並且通過b.intern() == d和b.intern() == f可知,字串相加的時候,都是靜態字串的結果會添加到字串池,如果其中含有變數(如f中的e)則不會進入字串池中。但是字串一旦進入字串池中,就會先尋找池中有無此對象。如果有此對象,則讓對象引用指向此對象。如果無此對象,則先建立此對象,再讓對象引用指向此對象。

當研究到這個地方的時候,突然想起來經常遇到的一個比較經典的Java問題,就是對比equal和==的區別,當時記得老師只是說“==”判斷的是“地址”,但是並沒說清楚什麼時候會有地址相等的情況。現在看來,在定義變數的時候賦值,如果賦值的是靜態字串,就會執行進入字串池的操作,如果池中含有該字串,則返回引用。

執行下面的代碼:

String a = "abc";String b = "abc";String c = "a" + "b" + "c";String d = "a" + "bc";String e = "ab" + "c";        System.out.println(a == b);System.out.println(a == c);System.out.println(a == d);System.out.println(a == e);System.out.println(c == d);System.out.println(c == e);

啟動並執行結果:

truetruetruetruetruetrue

 

《深入理解java虛擬機器》String.intern()探究

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.