java基礎類型源碼解析之String

差點忘了最經常使用的String類型,咱們對String的大多數方法都已經很熟了,這裏就挑幾個平時不會直接接觸的點來解析一下。java

先來看看它的成員變量數組

public final class String  {
    private final char value[];
    private int hash; // Default to 0
}
  • string的內容其實就是一個char數組;
  • hash字段緩存了string的哈希值,由於string常常做爲hashmap的key,這樣能提升性能;

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的哈希值採用一種延遲計算的策略,計算方法很簡單,就是把每一個char都當作int,經過公式h=31*h+char的計算最終值。因爲String是不可變對象,在生命週期內,hash值只須要計算一次。緩存

subString

public String substring(int beginIndex, int endIndex) {
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
            : new String(value, beginIndex, subLen);
}
public String(char value[], int offset, int count) {
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

注:上面的代碼爲了節省空間,省略了異常檢查邏輯安全

subString會建立一個全新的字符串,而不是共享原字符串的char數組。按道理講,因爲String是不可變的,那麼subString和原string共享char數組是安全的,多是出於其餘方面的考慮:雖然節省了一點空間,可是須要額外增長一個offset和size成員,總體效率未必更佳。性能

碼點(CodePoint)

簡單介紹一下碼點和碼元的概念,一個碼點是某種字符編碼方案裏面,某個字符對應的絕對編碼值。而碼元則是指具體的字符存儲方案下,最小的存儲單元。this

對java的String來講,存儲的是unicode字符,使用的編碼方案是utf-16,碼元是char(16bit); utf-16的大部分碼點用一個char足夠了,可是有少部分須要兩個char。編碼

咱們來看一段從碼點序列建立String的代碼:code

public String(int[] codePoints, int offset, int count) {
    final int end = offset + count;

    // Pass 1: Compute precise size of char[]
    int n = count;
    for (int i = offset; i < end; i++) {
        int c = codePoints[i];
        if (Character.isBmpCodePoint(c))
            continue;
        else if (Character.isValidCodePoint(c))
            n++;
        else throw new IllegalArgumentException(Integer.toString(c));
    }

    // Pass 2: Allocate and fill in char[]
    final char[] v = new char[n];

    for (int i = offset, j = 0; i < end; i++, j++) {
        int c = codePoints[i];
        if (Character.isBmpCodePoint(c))
            v[j] = (char)c;
        else
            Character.toSurrogates(c, v, j++);
    }

    this.value = v;
}
  • 一樣,上面的代碼刪除了異常處理邏輯;
  • 請注意,碼點用int來表示
  • 第一個循環,計算碼點數組codePoints,須要多少長度的char數組:
    • Character.isBmpCodePoint 判斷是否一個基本多文種平面碼點,這樣的碼點只需1個char
    • 不然須要兩個碼點,長度+1
  • 第二個循環,把碼點值通過轉換存入char數組
    • 若是是基本碼點,直接放入
    • 若是是非基本碼點,須要作一個計算,生成兩個char

所以,若是你要把String當作一段實際的文本,並處理當中的單個文字,經過遍歷char的方式是不行的,而要使用codePoint相關方法。關於編碼相關的知識,不是本文要講的內容,你們自行查閱資料。對象

相關文章
相關標籤/搜索