1. 程式人生 > >String原始碼解析(JDK1.8)

String原始碼解析(JDK1.8)

1、string類的定義

public final class String 
    implements java.io.Serializable, Comparable<String>, CharSequence {}
  • java.io.Serializable
    序列化介面沒有任何方法和域,僅用於標識序列化的語意

  • Comparable
    介面只有一個compareTo(T 0)介面,用於對兩個例項化物件比較大小

  • CharSequence
    介面是一個只讀的字元序列。包括length(), charAt(int index), subSequence(int start, int end)這幾個API介面,值得一提的是,StringBuffer和StringBuild也是實現了改介面

2、主要變數

/**用來儲存字串  */
private final char value[];

/** 快取字串的雜湊碼 */
private int hash; // Default to 0

/** 實現序列化的標識 */
private static final long serialVersionUID = -6849794470754667710L;

一個 String 字串實際上是一個 char 陣列。

3、構造方法
 String 類的構造方法很多。可以通過初始化一個字串,或者字元陣列,或者位元組陣列等等來建立一個 String 物件。
 在這裡插入圖片描述

String str1 = "abc";//注意這種字面量宣告的區別,文末會詳細介紹
String str2 = new String("abc");
String str3 = new String(new char[]{'a','b','c'});

4、常用方法

  • equals(Object anObject)
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

String 類重寫了 equals 方法,比較的是組成字串的每一個字元是否相同,如果都相同則返回true,否則返回false。

  • 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;
}

String 類的 hashCode 演算法很簡單,主要就是中間的 for 迴圈,計算公式如下:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

s 陣列即原始碼中的 val 陣列,也就是構成字串的字元陣列。這裡有個數字 31 ,為什麼選擇31作為乘積因子,而且沒有用一個常量來宣告?主要原因有兩個:

①、31是一個不大不小的質數,是作為 hashCode 乘子的優選質數之一。

②、31可以被 JVM 優化,31 * i = (i << 5) - i。因為移位運算比乘法執行更快更省效能。

  • charAt(int index)
public char charAt(int index) {
   //如果傳入的索引大於字串的長度或者小於0,直接丟擲索引越界異常
   if ((index < 0) || (index >= value.length)) {
       throw new StringIndexOutOfBoundsException(index);
   }
   //返回指定索引的單個字元
   return value[index];
}
  • compareTo(String anotherString) 和 compareToIgnoreCase(String str)

我們先看看 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;
}

原始碼也很好理解,該方法是按字母順序比較兩個字串,是基於字串中每個字元的 Unicode 值。當兩個字串某個位置的字元不同時,返回的是這一位置的字元 Unicode 值之差,當兩個字串都相同時,返回兩個字串長度之差。

compareToIgnoreCase() 方法在 compareTo 方法的基礎上忽略大小寫,我們知道大寫字母是比小寫字母的Unicode值小32的,底層實現是先都轉換成大寫比較,然後都轉換成小寫進行比較。

  • concat(String str)

該方法是將指定的字串連線到此字串的末尾。

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

首先判斷要拼接的字串長度是否為0,如果為0,則直接返回原字串。如果不為0,則通過 Arrays 工具類(後面會詳細介紹這個工具類)的copyOf方法建立一個新的字元陣列,長度為原字串和要拼接的字串之和,前面填充原字串,後面為空。接著在通過 getChars 方法將要拼接的字串放入新字串後面為空的位置。

注意:返回值是 new String(buf, true),也就是重新通過 new 關鍵字建立了一個新的字串,原字串是不變的。這也是前面我們說的一旦一個String物件被建立, 包含在這個物件中的字元序列是不可改變的。

  • indexOf(int ch) 和 indexOf(int ch, int fromIndex)

indexOf(int ch),引數 ch 其實是字元的 Unicode 值,這裡也可以放單個字元(預設轉成int),作用是返回指定字元第一次出現的此字串中的索引。其內部是呼叫 indexOf(int ch, int fromIndex),只不過這裡的 fromIndex =0 ,因為是從 0 開始搜尋;而 indexOf(int ch, int fromIndex) 作用也是返回首次出現的此字串內的索引,但是從指定索引處開始搜尋。


轉自:https://www.cnblogs.com/ysocean/p/8571426.html#_label0