java 基於JDK中的源碼總結下String二

        申明:轉載請註明出處,如有商用目的請務必知會本人,感謝。


        上一篇文章:http://blog.csdn.net/ts1122/article/details/8738336,介紹了String一些易錯內容。這裏接着大體介紹下String類提供的API。大體就是不對API做一一介紹,只是根據類型說個大概,再選擇一些經典的方法詳細說明下。說明下,這兩篇文章都是基於JDK1.7.0_17版本進行說明的,本文章後面的內容會說到JDK1.7版本String類的實現和JDK1.6版本還是很大不同的。
        先說構造方法,String類裏面構造方法很多。由於方法簽名只與方法名稱以及參數類型有關係,這麼多構造方法的差異就只能是傳遞的參數類型和數目。不過有的構造方法基本不會被用到,比如下面兩個:

public String() {
   this.value = new char[0];
}
public String(String original) {
   this.value = original.value;
   this.hash = original.hash;
}

第一個構造方法之所以不用,說明文檔裏面寫的很清楚:由於String是不可變的,當前方法的基本沒用。這個方法給出了一個指向空字符串的引用,之後指向的內容又不能改變,所以沒有什麼用處。Java裏面有些類叫做不可變類,其定義爲:類中的每個方法都不能改變其對象。一般這種類中的數據域都有加final修飾,String類就是一個不可變類,其數據域就加了final字符修飾。上面的第二個方法之所以不用是因爲會多分配一塊內存,JVM會在當前線程的stringpool中分配一塊內存,之後在堆中再分配一塊內存。構造一個String,我們一般只要用String = “abc”這種方式就足夠了,而且簡單高效,這種用法也是java推薦的。:-D
        下面是一組和String類數據域有關的方法:

public int length()
public boolean isEmpty()
public char charAt(int index)
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)

這三個方法都是基於String的數據域char value[]實現的,比如返回value.length。這些方法經常有用到,得記住。最後一個方法是將String中數據域內容拷貝到char數組方法,用System.arraycopy的本地方法實現,效率應該很高。
        接下來是一組String內容比較方法:

public boolean equals(Object anObject)
public boolean equalsIgnoreCase(String anotherString)
public boolean contentEquals(CharSequence cs)
public int compareTo(String anotherString)

第一個方法比較兩個字符串對象內容是否完全相等,如果是就返回true。第二個方法從方法名稱就可以理解,不考慮大小寫進行比較。看了下第二個方法的內部實現,先把字符統一轉成大寫進行比較,如果不行再轉成小寫進行比較,看說明文檔對於Georgian alphabet就有這種大寫不成要用小寫的特殊情況。:-(   第三個方法和前面兩個方法基本一樣,只不過參數類型不同。最後一個方法和C語言中的一樣:取兩個字符串較短的長度,從第一個字符開始對兩個字符串進行比較,如果出現第一個不同的字符則返回兩個字符之間的差值。結果返回是0的話就說明兩個字符串內容相等。但是這個方法在java中很少用到。
        一組新的字符串內容比較方法:

public int indexOf(int ch)
public int indexOf(int ch, int fromIndex) 
public int lastIndexOf(int ch)
public boolean startsWith(String prefix) 
public boolean startsWith(String prefix, int toffset)
public boolean endsWith(String suffix)
public int indexOf(String str)
public int indexOf(String str, int fromIndex)
public int lastIndexOf(String str)

前面三個方法都是返回一個字符在當前字符串中的位置。後面一組方法是尋找一組字符串在當前字符串中的位置,和前面一組方法很相似。
        一組易被忽視會產生新的字符串對象的方法:

public String substring(int beginIndex)
public String substring(int beginIndex, int endIndex)
public String replace(char oldChar, char newChar)
public String toLowerCase()
public String toUpperCase()
public String trim()

這些都是對當前字符串內容進行截取,替換,大小寫變更等操作的方法。由於String類是不可變類,這些方法不能改變對象內容,只能新分配內存保存操作結果,如果濫用這些方法會造成內存泄露的。
        這裏根據public String substring(int beginIndex)說一下JDK1.6和JDK1.7String類的一些不同。JDK1.6上String類的數據域如下:

/** The value is used for character storage. */
private final char value[];

/** The offset is the first index of the storage that is used. */
private final int offset;

/** The count is the number of characters in the String. */
private final int count;

即其包含一個類似高中幾何上向量的東西,給出內容同時還給出了一個起始點和長度的遊標。JDK1.6中在實現substring最終會用到下面的方法:

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
   this.value = value;
   this.offset = offset;
   this.count = count;
}

這就是說截取一段某一個字符串中的一段,實際上並沒有分配新的內存,只是提供了一個新的向量,返回的引用仍然指向原來的字符串。如果原來的字符串不再使用,僅使用新的截取的字符串,個人認爲就造成內存浪費。如果每次都是從一個很長很長字符串中截取一小段內容,就造成了內存的極大浪費,這也是JDK1.6使用過程中,關於字符串的一個優化點。再看JDK1.7中String類就只有char value[]一個數據域,方法substring就採取了新的做法,如下:  

 this.value = Arrays.copyOfRange(value, offset, offset+count);

這句代碼完成這個方法實現主體,分配了新的內存,將需要的內容拷貝到新的內存中。看JDK文檔中說明,1.6的這種做法是爲了速度。:-D
       接下來就是valueOf方法,都是像    public static String valueOf(Object obj) 這樣的類方法,這些方法的實現其實就是參數本身的toString方法的實現。最後就是split方法,這個涉及到了正則表達式,這裏暫不介紹。:-D

發佈了46 篇原創文章 · 獲贊 28 · 訪問量 70萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章