jdk源碼閱讀之——String類

          最近有很多空閒的時間,正好可以用來看看jdk一些常用類的源碼。閱讀源碼可以讓我在使用這些API的時候可以知其所以然,

還可以領略大師的代碼。好了,廢話不多說了。

1.String類的定義

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence 

   從定義可以看到,String類使用了final關鍵字修飾,這就是爲什麼String類不能夠被繼承的原因。之所以這樣做,主要是爲了效率和 安全性的緣故。

    String也實現了Serializable接口,說明他是可序列化的。由於它也實現了Comparable接口,所以已經實現了排序的算法。


String內部的實現是通過一個char型的數組實現的,如下所示:

private final char value[];

  可以看到value數組也使用了final關鍵字修飾,這決定了String是不可變類,final 修飾數組或對象時,對象地址不可變,但堆內存中的內容還可變。


    2.String的構造方法。

String類總共有15個構造方法,所以可以通過各種各樣的方式來創建一個String對象。String構造方法的文檔:

構造方法摘要
String() 
          初始化一個新創建的 String 對象,使其表示一個空字符序列。
String(byte[] bytes) 
          通過使用平臺的默認字符集解碼指定的 byte 數組,構造一個新的 String
String(byte[] bytes, Charset charset) 
          通過使用指定的 charset 解碼指定的 byte 數組,構造一個新的 String
String(byte[] ascii, int hibyte) 
          已過時。 該方法無法將字節正確地轉換爲字符。從 JDK 1.1 開始,完成該轉換的首選方法是使用帶有 Charset、字符集名稱,或使用平臺默認字符集的 String 構造方法。
String(byte[] bytes, int offset, int length) 
          通過使用平臺的默認字符集解碼指定的 byte 子數組,構造一個新的 String
String(byte[] bytes, int offset, int length, Charset charset) 
          通過使用指定的 charset 解碼指定的 byte 子數組,構造一個新的 String
String(byte[] ascii, int hibyte, int offset, int count) 
          已過時。 該方法無法將字節正確地轉換爲字符。從 JDK 1.1 開始,完成該轉換的首選方法是使用帶有 Charset、字符集名稱,或使用平臺默認字符集的 String 構造方法。
String(byte[] bytes, int offset, int length, String charsetName) 
          通過使用指定的字符集解碼指定的 byte 子數組,構造一個新的 String
String(byte[] bytes, String charsetName) 
          通過使用指定的 charset 解碼指定的 byte 數組,構造一個新的 String
String(char[] value) 
          分配一個新的 String,使其表示字符數組參數中當前包含的字符序列。
String(char[] value, int offset, int count) 
          分配一個新的 String,它包含取自字符數組參數一個子數組的字符。
String(int[] codePoints, int offset, int count) 
          分配一個新的 String,它包含 Unicode 代碼點數組參數一個子數組的字符。
String(String original) 
          初始化一個新創建的 String 對象,使其表示一個與參數相同的字符序列;換句話說,新創建的字符串是該參數字符串的副本。
String(StringBuffer buffer) 
          分配一個新的字符串,它包含字符串緩衝區參數中當前包含的字符序列。
String(StringBuilder builder) 
          分配一個新的字符串,它包含字符串生成器參數中當前包含的字符序列。

 3.String的hashcode算法的實現。

  public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
            for (int i = 0; i < value.length; i++) {

                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

  以abc爲例。根據hashcode()源碼中的循環部分的算法,計算一下abc的hashcode值.a,b,c 的ascii碼值分別爲97,98,99;字符個數3

總共有3次循環
1:h=31*0+val[0]=val[0]='a'=97
2:h=31*h+val[1]=31*97+'b'=31*97+98=3105
3:h=31*h+val[2]=31*3166+'c'=31*3105+99=96354
所以abc的hashcode值爲96354

  至於爲什麼要選擇31這個數字作爲基數,網上有很多是解答,我認爲主要是以下幾個原因:
1.    31是質數,質數的特性(只有1和自己是因子)能夠使得它和其他數相乘後得到的結果比其他方式更容易產成唯一性,也就是hash code值的衝突概率最小。
2.    選擇31是觀測分佈結果後的一個選擇,不清楚原因,但的確有利。

3.    31*N可以被編譯器優化爲左移5位後減1,有較高的性能。



4.String的排序算法的實現。

     由於它也實現了Comparable接口,下面看看它的compareTo方法

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

   可以看到,最多比較lim次,既較短的字符串的長度。從0下表的字符開始,依次比較,如果相同,繼續。如果不相同,返回兩個字符的差值。如果較短字符串與較長字符串的前幾位相同,則返回兩個字符串的長度的差值。


String類還有很多功能強大的方法,由於時間的關係,就不一一分析了。先寫到這裏吧。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章