String這個類,是Java中很經典的類,從我們學Java的那天起就與他結下“梁子”,在以後的日子他更是如影隨形,對你不離不棄。所以,瞭解String,理解String很有必要。
1. 簡介
看看JDK中對String類的描述:
public final class String extends Object<br />implements Serializable, Comparable<String>, CharSequence
該類是一個final類,子類無法繼承。實現了Serializable、Comparable<String>、CharSequence三個介面。很多公司的Java面試題,都會與String有關,畢竟處理字串是很頻繁的,再者很多演算法也和String有關。
2. intern方法
intern<br />public String intern()<br />返回字串對象的正常化表示形式。<br />一個初始為空白的字串池,它由類 String 私人地維護。<br />當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字串(用 equals(Object) 方法確定),則返回池中的字串。否則,將此 String 對象添加到池中,並返回此 String 對象的引用。<br />它遵循以下規則:對於任意兩個字串 s 和 t,若且唯若 s.equals(t) 為 true 時,s.intern() == t.intern() 才為 true。<br />所有字面值字串和字串賦值常量運算式都使用 intern 方法進行操作。字串字面值在 Java Language Specification 的 §3.10.5 定義。<br />返回:<br />一個字串,內容與此字串相同,但一定取自具有唯一字串的池。
在具體介紹intern方法之前,舉個例子,以便於更好地說明我的問題。
package mark.zhang;<br />public class Linux {</p><p>public static void main(String[] args) {<br />String s1 = "ubuntu";<br />String s2 = "ubuntu";<br />System.out.println(s1.equals(s2));//true<br />System.out.println(s1 == s2);//true</p><p>String s3 = new String("ubuntu");<br />String s4 = new String("ubuntu");<br />System.out.println(s3.equals(s4));//true<br />System.out.println(s3 == s4);//false<br />}<br />}<br />
我該保證,大多數人都是知道結果的。不過在這裡,我還是想用記憶體來分析一下結果。
字串常量會放在常量池中,(常量池主要存放字串常量和基本類型常量(public static final))。有些人的部落格中說常量放在data segement中,我想data segement主要用來存放靜態變數(這裡的變數是指成員變數,因為static不可以修飾局部臨時變數)和字串常量和基本類型常量等。所以,data segement可以分為靜態地區以及常量池等。
知道這些概念之後,分析上面代碼就會顯得很輕鬆啦,來吧,一起分析!!!
String s1 = "ubuntu";
這句代碼,執行時會在常量池中尋找是否有ubuntu,如果有的話,就指向它,沒有的話就自己建立。接著,建立s2,同理s2找到ubuntu,如是就不會自己再在常量池中建立ubuntu啦。這樣一來,s1和s2都指向了常量池中的ubuntu。
既然s1與s2都指向一個地方,所以 == 就是true。
String s3 = new String("ubuntu");<br />String s4 = new String("ubuntu");
那麼,我們看看,這兩句代碼的記憶體分析。首先需要明白,new出來的東西放在堆記憶體中。s3會先在常量池中看看有沒有ubuntu,沒有的話就先在常量池中建立一個,然後對中對象執行個體其實是常量池中的一份拷貝。s4發現常量池中已經存在ubuntu,直接在堆中拷貝一份。
從上面來看,s3、s4分別指向不同地址的ubuntu,所以二者就不會==。
好了,回到今天的主題intern方法。我想,如果你明白上面的內容,下面所講的東西對您來說就會很簡單,跟喝水差不多,呵呵!!
package mark.zhang;<br />public class Linux {</p><p>public static void main(String[] args) {<br />String s1 = "ubuntu";<br />String s2 = new String("ubuntu");<br />System.out.println("invoke intern before: ");<br />System.out.println(s1 == s2);//false<br />s2 = s2.intern();<br />System.out.println("invoke intern after: ");<br />System.out.println(s1 == s2);//true<br />}<br />}
也許,你會問結果怎麼會與自己預想不一樣??從這個例子,可以明白intern返回的是常量池中的字串的值。只有這樣,兩個對象才會==,這也充分說明無論以哪種方式建立的字串對象,都會先在常量池中建立一個字串(內容即字面值)。再看下面一個例子,算是對intern及以上所說的一點補充吧?!
package mark.zhang;<br />public class Linux {</p><p>public static void main(String[] args) {</p><p>String s1 = new String("redhat");<br />String s2 = new String("redhat");<br />s2 = s2.intern(); // 返回常量池中的redhat<br />// 但是s1指向堆裡面的對象,而不是常量池中的redhat<br />System.out.println(s2 == s1);//false</p><p>String s3 = new String("redhat");<br />String s4 = new String("redhat");<br />s3 = s3.intern(); // 返回常量池中的redhat<br />s4 = s4.intern(); // 返回常量池中的redhat<br />System.out.println(s3 == s4);//true<br />}<br />}<br />
ok,收工!歡迎拍磚,共同進步!