首先,先看一下intern方法(JDK1.8)的官方文檔: 全是英文,閱讀起來有點困難怎麼辦?沒關係,博主對此做了翻譯: 返回字元串對象的規範表示形式。 最初為空的字元串池由類字元串私人維護。 調用intern方法時,如果池中已包含一個字元串,該字元串等於由equals(object)方法確定的該字 ...
首先,先看一下intern方法(JDK1.8)的官方文檔:
全是英文,閱讀起來有點困難怎麼辦?沒關係,博主對此做了翻譯:
返回字元串對象的規範表示形式。
最初為空的字元串池由類字元串私人維護。
調用intern方法時,如果池中已包含一個字元串,該字元串等於由equals(object)方法確定的該字元串對象,則返回池中的字元串。否則,將此字元串對象添加到池中,並返回對該字元串對象的引用。
因此,對於任意兩個字元串s和t,s.intern()==t.intern()當且僅當s.equals(t)為真時才為真。
所有文字字元串和字元串值常量表達式都是內部的。字元串文字在Java的第3.10.5節中定義™ 語言規範。
返回值:
與此字元串具有相同內容,但保證來自唯一字元串池的字元串。
還是看不懂怎麼辦?以下博主將對intern方法進行全面講解:
要想具體瞭解String中的intern方法,首先你要瞭解一下JVM的記憶體結構,認識串池(StringTable)。
以下是JDK1.6相關的記憶體結構:
以下是JDK1.8相關的記憶體結構:
隨著記憶體結構的改變String中的intern方法功能也發生了改變。
本片文章主要以JDK1.8為例,先看以下這段代碼:
public class Test{ String s1 = new String("a") + new String("b"); s1.intern();//① String s2 = "ab";//② System.out.println(s1 == s2); }
運行結果為true;
具體原因是:當String對象調用intern方法時,如果池中未包含相同的字元串,將此字元串對象添加到池中,並返回對該字元串對象的引用。
運行的主要流程為:
(1)String s1 = new String(“a”) + new String(“b”);
首先創建StringBuilder對象,用於字元串拼接;
然後在堆中創建了String(“a”)對象,然後在字元串常量池中放入字元串"a",再做StringBuilder的append操作;
然後在堆中創建了String(“b”)對象,然後在字元串常量池中放入字元串"b",再做StringBuilder的append操作;
最後對StringBuilder做toString操作,註意此時只會在堆記憶體創建對象,並不會在串池中創建。
(2)s1.intern();
常量池中不直接放入"ab",而是引用堆中已經創建的String(“ab”)。
(3)String s2 = “ab”;
s2指向字元串常量池中的"ab",實際上是指向了堆中的String(“ab”)。
但當我們調換①和②的位置時結果為falus,這是什麼原因呢?
調用intern方法時,如果池中已包含一個字元串,該字元串等於由equals(object)方法確定的該字元串對象,則返回池中的字元串。
所以,當調換①和②後,代碼將會首先在串池中創建一個“ab”,然後當執行s1.intern()時就會直接返回串池中的"ab",但此時堆記憶體中的String("ab")對象和串池中的"ab"不為同一個,於是返回falus。
但別忘了,JDK1.6和JDK1.8卻是不同的。
JDK1.6的作用是:檢查常量池裡是否存在“ab”這麼一個字元串,如果存在,就返回池裡的字元串,如果不存在,該方法會把“ab”添加到字元串池中(此時這個"ab"並不是堆記憶體中的那個String(”ab“)而是一個新的"ab"),然後再返回它的引用。所以如果是JDK1.6下以上兩張情況將都返回falus。