String 源碼淺析————終結篇

寫在前面

說說這幾天看源碼的感覺吧,其實 jdk 中的源碼設計是最值得進階學習的地方。咱們在對 api 較爲熟悉以後,徹底能夠去嘗試閱讀一些 jdk 源碼,打開 jdk 源碼後,若是你英文能力稍微過得去,那麼源碼有至關詳細的註釋告訴你 api 的含義,具體用法。假設平時在寫代碼的過程當中忽然忘記了某個 api 的用法,那麼有些新手沒讀過源碼的可能順手就打開百度或者谷歌,搜索 api 怎麼用?哈哈哈,面向谷歌編程,這樣的狀態可能會讓你一年的經驗重複n年, 若是是閱讀過源碼,則直接進去看看源碼英文註釋,回想一下源碼的實現便可使用,並且看過源碼後,裏面有些代碼細節是能夠在平時編碼的過程當中直接借鑑的。html

廢話有點多啦~~滴滴滴,上車了。。。java

上一篇 String 源碼淺析(一) 中已經對String前半部分源碼作了解析,這篇把剩下的方法粗略的總結下…正則表達式

String 成員方法

  • 判斷字符串是否相等,該方法繼承自Object類的重寫實現,原則上也是比較字符串中的字符是否相等。編程

     1   public boolean equals(Object anObject) {
    2    //判斷形參跟當前字符串對象地址是否相等,便是否爲同一個對象,若是相等,則返回true
    3    if (this == anObject) {
    4        return true;
    5    }
    6    //若是形參爲String類型對象
    7    if (anObject instanceof String) {
    8        //強轉爲String類型對象
    9        String anotherString = (String)anObject;
    10        //當前字符串對象的字符數組長度
    11        int n = value.length;
    12        //若是當前字符串對象的字符數組長度等於形參字符串字符數組長度
    13        if (n == anotherString.value.length) {
    14            //當前字符串字符數組
    15            char v1[] = value;
    16            //形參字符串字符數組
    17            char v2[] = anotherString.value;
    18            //遍歷索引發始位置0
    19            int i = 0;
    20            //遍歷當前字符串字符數組,每一個索引位置的字符與形參字符串索引位置字符比較,若是不相等則返回false
    21            while (n-- != 0) {
    22                if (v1[i] != v2[i])
    23                    return false;
    24                i++;
    25            }
    26            return true;
    27        }
    28    }
    29    //以上條件都不知足,最後返回false
    30    return false;
    31}
  • 傳入CharSequence接口形參,實際是與StringBuffer,StringBuilder比較是否相等,由於StringBuffer,StringBuilder都實現了CharSequence接口api

     1public boolean contentEquals(CharSequence cs) {
    2    //判斷形參是不是AbstractStringBuilder抽象類,實則因當傳入的是其子類:StringBuffer, StringBuilder
    3    if (cs instanceof AbstractStringBuilder) {
    4        //若是形參是StringBuffer類型對象
    5        if (cs instanceof StringBuffer) {
    6            //同步鎖,調用nonSyncContentEquals方法比較兩種是否相等
    7            synchronized(cs) {
    8               return nonSyncContentEquals((AbstractStringBuilder)cs);
    9            }
    10        } else {
    11            //若是形參對象是StringBuilder,則調用nonSyncContentEquals方法比較兩種是否相等
    12            return nonSyncContentEquals((AbstractStringBuilder)cs);
    13        }
    14    }
    15    // 若是形參是String對象,則直接調用equals方法返回
    16    if (cs instanceof String) {
    17        return equals(cs);
    18    }
    19    // 若是是其餘的CharSequence實現類,則遍歷,一個個字符進行比較,找到一個字符不相等則直接返回false
    20    char v1[] = value;
    21    int n = v1.length;
    22    if (n != cs.length()) {
    23        return false;
    24    }
    25    for (int i = 0; i < n; i++) {
    26        if (v1[i] != cs.charAt(i)) {
    27            return false;
    28        }
    29    }
    30    //以上代碼都不成立,走到最後直接返回true
    31    return true;
    32}
  • 私有方法,非同步方式(線程不安全)比較與 AbstractStringBuilder 是否相等,實則是與其子類:StringBuffer, StringBuilder 比較大小,contentEquals(CharSequence cs)方法中核心比較代碼就是調用該方法。數組

     1  private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
    2    //當前字符串對象字符數組
    3    char v1[] = value;
    4    //獲取形參字符數組
    5    char v2[] = sb.getValue();
    6    //當前字符串對象字符數組長度
    7    int n = v1.length;
    8    //若是當前字符串對象字符數組長度不等於形參字符數組長度,則直接返回false
    9    if (n != sb.length()) {
    10        return false;
    11    }
    12    //遍歷當前字符串對象字符數組,與形參字符數組逐一比較字符,找到一個字符不相等,則直接返回false
    13    for (int i = 0; i < n; i++) {
    14        if (v1[i] != v2[i]) {
    15            return false;
    16        }
    17    }
    18    //以上條件都不成立,代碼走到最後則直接返回true
    19    return true;
    20}
  • 公有方法,比較與StringBuffer對象是否相等,內部實則直接調用的contentEquals(CharSequence cs)方法,能夠說該方法是StringBuffer的特別版吧。安全

    1  public boolean contentEquals(StringBuffer sb) {
    2    return contentEquals((CharSequence)sb);
    3}
  • 匹配兩個字符串部分片斷是否相等app

     1  public boolean regionMatches(int toffset, String other, int ooffset,
    2        int len)
     
    {
    3    //當前字符串字符數組
    4    char ta[] = value;
    5    //當前字符串開始比較的起始位置,即偏移量
    6    int to = toffset;
    7    //待比較的字符串字符數組
    8    char pa[] = other.value;
    9    //待比較的字符串起始位置,即偏移量
    10    int po = ooffset;
    11    //索引檢查 1.偏移量小於0  2. 偏移量大於總長度-待比較的長度
    12    //以上兩種狀況直接返回false
    13    if ((ooffset < 0) || (toffset < 0)
    14            || (toffset > (long)value.length - len)
    15            || (ooffset > (long)other.value.length - len)) {
    16        return false;
    17    }
    18    //遍歷,找出不相等的字符,則返回false
    19    while (len-- > 0) {
    20        if (ta[to++] != pa[po++]) {
    21            return false;
    22        }
    23    }
    24    //不出意外,最終則返回true
    25    return true;
    26}
  • 匹配兩個字符串部分片斷是否相等,同時判斷是否忽略大小寫post

     1public boolean regionMatches(boolean ignoreCase, int toffset,
    2        String other, int ooffset, int len)
     
    {
    3    //當前字符串字符數組
    4    char ta[] = value;
    5    //當前字符串開始比較的起始位置,即偏移量
    6    int to = toffset;
    7    //待比較的字符串字符數組
    8    char pa[] = other.value;
    9    //待比較的字符串起始位置,即偏移量
    10    int po = ooffset;
    11    //索引檢查 1.偏移量小於0  2. 偏移量大於總長度-待比較的長度
    12    //以上兩種狀況直接返回false
    13    if ((ooffset < 0) || (toffset < 0)
    14            || (toffset > (long)value.length - len)
    15            || (ooffset > (long)other.value.length - len)) {
    16        return false;
    17    }
    18    //遍歷檢查字符是否相等,相等則跳過
    19    while (len-- > 0) {
    20        char c1 = ta[to++];
    21        char c2 = pa[po++];
    22        if (c1 == c2) {
    23            continue;
    24        }
    25        //若是字符不相等,且須要忽略大小寫比較
    26        if (ignoreCase) {
    27            //字符轉換爲大寫
    28            char u1 = Character.toUpperCase(c1);
    29            char u2 = Character.toUpperCase(c2);
    30            //若是相等,則繼續跳過
    31            if (u1 == u2) {
    32                continue;
    33            }
    34            //轉換爲小寫進行比較,若是相等則繼續跳過
    35            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
    36                continue;
    37            }
    38        }
    39        //不然發現不相等,則直接返回false
    40        return false;
    41    }
    42    //不出意外,最終返回true
    43    return true;
    44}
  • 忽略大小寫比較字符串大小學習

     1 public boolean equalsIgnoreCase(String anotherString) {
    2    //一句三目運算直接搞定
    3    //若是當前字符串對象地址與形參字符串相等,則返回true
    4    //不然判斷形參字符串是否爲空,形參字符串長度是否與當前字符串長度相等,直接調用regionMatches比較兩個字符串全部字符是否相等,同時忽略大小寫比較
    5    //以上所有爲true則相等
    6    return (this == anotherString) ? true
    7            : (anotherString != null)
    8            && (anotherString.value.length == value.length)
    9            && regionMatches(true0, anotherString, 0, value.length);
    10}
  • 比較兩個字符串是否相等,該方法實現自Comparable接口,返回 int 結果,等於0,則字符串相等,小於0,則前者小於後者,大於0,則前者大於後者

     1  public int compareTo(String anotherString) {
    2    //當前字符串字符數組長度
    3    int len1 = value.length;
    4    //待比較字符串字符數組長度
    5    int len2 = anotherString.value.length;
    6    //獲取較小的長度
    7    int lim = Math.min(len1, len2);
    8    //當前字符串字符數組
    9    char v1[] = value;
    10    //待比較的字符串字符數組
    11    char v2[] = anotherString.value;
    12    //索引位置0開始
    13    int k = 0;
    14    //遍歷較小的字符數組
    15    while (k < lim) {
    16        char c1 = v1[k];
    17        char c2 = v2[k];
    18        //若是字符不相等
    19        if (c1 != c2) {
    20            //返回字符之差
    21            return c1 - c2;
    22        }
    23        k++;
    24    }
    25    //若是字符都相等,則返回長度之差
    26    return len1 - len2;
    27}
  • 使用默認比較器不區分大小寫比較兩個字符串大小

     1//初始化默認的比較器
    2public static final Comparator<String> CASE_INSENSITIVE_ORDER
    3                                     = new CaseInsensitiveComparator();
    4//默認的比較器,不區分大小寫                          
    5private static class CaseInsensitiveComparator
    6        implements Comparator<String>, java.io.Serializable 
    {
    7    // use serialVersionUID from JDK 1.2.2 for interoperability
    8    private static final long serialVersionUID = 8575799808933029326L;
    9    public int compare(String s1, String s2) {
    10        //第一個字符串長度
    11        int n1 = s1.length();
    12        //第二個字符串長度
    13        int n2 = s2.length();
    14        //取小
    15        int min = Math.min(n1, n2);
    16        //遍歷較小的字符串
    17        for (int i = 0; i < min; i++) {
    18            //獲取指定索引字符
    19            char c1 = s1.charAt(i);
    20            char c2 = s2.charAt(i);
    21            //若是字符不相等
    22            if (c1 != c2) {
    23                //轉化爲大寫
    24                c1 = Character.toUpperCase(c1);
    25                c2 = Character.toUpperCase(c2);
    26                //轉化爲大寫後比較,不相等
    27                if (c1 != c2) {
    28                    //轉化爲小寫繼續比較
    29                    c1 = Character.toLowerCase(c1);
    30                    c2 = Character.toLowerCase(c2);
    31                    //轉化爲小寫字符,不相等
    32                    if (c1 != c2) {
    33                        //直接返回字符之差
    34                        return c1 - c2;
    35                    }
    36                }
    37            }
    38        }
    39        //不出意外,最終返回長度之差
    40        return n1 - n2;
    41    }
    42    /** Replaces the de-serialized object. */
    43    private Object readResolve() return CASE_INSENSITIVE_ORDER; }
    44}
    45
    46//內部直接調用默認比較器的compare方法
    47public int compareToIgnoreCase(String str) {
    48    return CASE_INSENSITIVE_ORDER.compare(this, str);
    49}
  • 從指定偏移量開始,判斷是否以指定字符串開頭

     1 public boolean startsWith(String prefix, int toffset) {
    2    //當前字符串字符數組
    3    char ta[] = value;
    4    //偏移量
    5    int to = toffset;
    6    //指定字符串前綴字符數組
    7    char pa[] = prefix.value;
    8    //索引位置0開始
    9    int po = 0;
    10    //指定字符串前綴數組長度
    11    int pc = prefix.value.length;
    12    //偏移量小於0 或者 //偏移量大於總長度-字符串前綴長度,則直接返回false
    13    if ((toffset < 0) || (toffset > value.length - pc)) {
    14        return false;
    15    }
    16    //遍歷前綴字符串
    17    while (--pc >= 0) {
    18        //從偏移量開始檢索,找到字符不相等,則返回false
    19        if (ta[to++] != pa[po++]) {
    20            return false;
    21        }
    22    }
    23    //不出意外,最後則返回true
    24    return true;
    25}
  • 從字符串開頭,判斷是否以指定字符串開頭

    1 public boolean startsWith(String prefix) {
    2    //直接調用startsWith重載方法,偏移量爲0
    3    return startsWith(prefix, 0);
    4}
  • 判斷是否以指定字符串結尾,內部直接調用的 startsWith 方法,偏移量爲總字符串長度-後綴字符串長度便可。

    1public boolean endsWith(String suffix) {
    2    return startsWith(suffix, value.length - suffix.value.length);
    3}
  • 從指定偏移量開始,搜索指定字符在字符串中第一次出現的索引位置

     1 public int indexOf(int ch, int fromIndex) {
    2    //當前字符串字符數組長度
    3    final int max = value.length;
    4    //若是偏移量小於0,則重置爲0
    5    if (fromIndex < 0) {
    6        fromIndex = 0;
    7    } else if (fromIndex >= max) {
    8        //偏移量大於總長度,則返回-1,意味着找不到指定字符
    9        return -1;
    10    }
    11    if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
    12        //當前字符串字符數組
    13        final char[] value = this.value;
    14        //從偏移量位置開始遍歷
    15        for (int i = fromIndex; i < max; i++) {
    16            //找到相等的字符,則返回索引
    17            if (value[i] == ch) {
    18                return i;
    19            }
    20        }
    21        //找不到則返回-1
    22        return -1;
    23    } else {
    24        return indexOfSupplementary(ch, fromIndex);
    25    }
    26}
  • 查找指定字符在字符串中第一次出現的索引位置,從偏移量0開始遍歷查找

    1 public int indexOf(int ch) {
    2    return indexOf(ch, 0);
    3}
  • 查找指定字符在字符串中最後一次出現的索引位置,從指定偏移量開始遍歷

     1  public int lastIndexOf(int ch, int fromIndex) {
    2    if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
    3        //當前字符串字符數組
    4        final char[] value = this.value;
    5        //偏移量與字符串最後的位置取小
    6        int i = Math.min(fromIndex, value.length - 1);
    7        //從後遍歷字符數組
    8        for (; i >= 0; i--) {
    9            //找到相等的字符,返回索引
    10            if (value[i] == ch) {
    11                return i;
    12            }
    13        }
    14        //找不到則返回-1
    15        return -1;
    16    } else {
    17        return lastIndexOfSupplementary(ch, fromIndex);
    18    }
    19}
  • 查找指定字符在字符串中最後一次出現的索引位置,從字符串最後一個索引位置開始遍歷查找

    1 public int lastIndexOf(int ch) {
    2    return lastIndexOf(ch, value.length - 1);
    3}
  • 從指定位置開始,查找字符串在源字符串中第一次出現的的索引位置,內部實則直接調用的indexOf內部靜態方法

    1  public int indexOf(String str, int fromIndex) {
    2    return indexOf(value, 0, value.length,
    3            str.value, 0, str.value.length, fromIndex);
    4}
  • 查找字符串在源字符串中第一次出現的的索引位置,內部實則直接調用的上述indexOf方法,fromIndex默認從0開始

    1 public int indexOf(String str) {
    2    return indexOf(str, 0);
    3}
  • 從指定位置開始,查找字符串在源字符串中最後一次出現的的索引位置,內部實則直接調用的lastIndexOf內部靜態方法

    1 public int lastIndexOf(String str, int fromIndex) {
    2    return lastIndexOf(value, 0, value.length,
    3            str.value, 0, str.value.length, fromIndex);
    4}
  • 查找字符串在源字符串中最後一次出現的的索引位置,內部實則直接調用的上述lastIndexOf方法,fromIndex默認從value.length開始

    1public int lastIndexOf(String str) {
    2    return lastIndexOf(str, value.length);
    3}
  • 按照指定區間裁剪字符串,返回子字符串,beginIndex起始位置(包含),endIndex結束位置(不包含)

     1    public String substring(int beginIndex, int endIndex) {
    2    //起始位置小於0,拋出索引越界異常
    3    if (beginIndex < 0) {
    4        throw new StringIndexOutOfBoundsException(beginIndex);
    5    }
    6    //結束位置大於字符串總長度,則拋出索引越界異常
    7    if (endIndex > value.length) {
    8        throw new StringIndexOutOfBoundsException(endIndex);
    9    }
    10    //待截取的字符串長度
    11    int subLen = endIndex - beginIndex;
    12    //待截取的字符串長度小於0,則拋出索引越界異常
    13    if (subLen < 0) {
    14        throw new StringIndexOutOfBoundsException(subLen);
    15    }
    16    //三目判斷 起始位置等於0,而且結束位置等於字符串長度,則表示爲截取總長度,返回當前字符串對象
    17    //不然從新new一個字符串實例,從beginIndex開始,截取subLen長度
    18    return ((beginIndex == 0) && (endIndex == value.length)) ? this
    19            : new String(value, beginIndex, subLen);
    20}
  • 從起始位置beginIndex開始截取源字符串到結尾,返回子字符串

     1 public String substring(int beginIndex) {
    2    //起始位置小於0,拋出索引越界異常
    3    if (beginIndex < 0) {
    4        throw new StringIndexOutOfBoundsException(beginIndex);
    5    }
    6    //待截取的字符串長度
    7    int subLen = value.length - beginIndex;
    8    //待截取的字符串長度小於0,則拋出索引越界異常
    9    if (subLen < 0) {
    10        throw new StringIndexOutOfBoundsException(subLen);
    11    }
    12    //三目判斷 起始位置等於0,則表示爲截取總長度,返回當前字符串對象,不然從新new一個新的字符串實例,從beginIndex開始,截取subLen長度
    13    return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    14}
  • 按照指定區間裁剪字符串,返回CharSequence接口,beginIndex起始位置(包含),endIndex結束位置(不包含),內部實則直接調用的substring方法,只是返回的是最上層接口罷了

    1 public CharSequence subSequence(int beginIndex, int endIndex) {
    2    return this.substring(beginIndex, endIndex);
    3}
  • 字符串拼接,將目標字符串拼接在尾部,返回新的字符串

     1  public String concat(String str) {
    2    //待拼接的字符串長度
    3    int otherLen = str.length();
    4    //若是待拼接的字符串長度等於0,則直接返回當前字符串對象
    5    if (otherLen == 0) {
    6        return this;
    7    }
    8    //當前字符串長度
    9    int len = value.length;
    10    //將當前字符串字符數組拷貝到新的字符數組buf[]中,長度擴容至len + otherLen
    11    char buf[] = Arrays.copyOf(value, len + otherLen);
    12    //將待拼接的字符數組拷貝至buf[]中,從len開始,理論上這部操做完以後,字符數組已經拼接成功了
    13    str.getChars(buf, len);
    14    //利用最新的字符數組,從新new一個新的字符串實例返回
    15    return new String(buf, true);
    16}
  • 將字符串中指定字符oldChar替換爲新的字符newChar

     1  public String replace(char oldChar, char newChar) {
    2    //若是舊的字符跟新的字符不相等,才執行替換邏輯,不然直接返回當前字符串對象
    3    if (oldChar != newChar) {
    4        //當前字符串長度
    5        int len = value.length;
    6        //索引從-1開始
    7        int i = -1;
    8        //當前字符串字符數組
    9        char[] val = value;
    10        //遍歷當前字符數組,從0開始,由於++i以後等於0
    11        while (++i < len) {
    12            //找到與oldChar相等的字符,則中斷循環
    13            if (val[i] == oldChar) {
    14                break;
    15            }
    16        }
    17        //若是oldChar索引位置i小於當前字符數組長度,意味着在當前字符串中找到了oldChar
    18        if (i < len) {
    19            //初始化字符串長度的字符數組
    20            char buf[] = new char[len];
    21            //從0開始遍歷到oldChar所在位置,將字符放入buf
    22            for (int j = 0; j < i; j++) {
    23                buf[j] = val[j];
    24            }
    25            //從oldChar索引位置i開始遍歷到字符串結尾
    26            while (i < len) {
    27                //當前字符
    28                char c = val[i];
    29                //若是當前字符等於oldChar,則newChar賦值給buf[i],不然不變
    30                buf[i] = (c == oldChar) ? newChar : c;
    31                i++;
    32            }
    33            //最後根據buf數組從新new一個新的字符串實例返回
    34            return new String(buf, true);
    35        }
    36    }
    37    return this;
    38}
  • 根據字符串正則regex匹配字符串,返回boolean,內部實則是調用正則匹配的api方法

    1public boolean matches(String regex) {
    2    return Pattern.matches(regex, this);
    3}
  • 判斷字符串是否包含指定字符序列CharSequence,內部實則是調用indexOf方法,判斷返回結果是否大於-1

    1 public boolean contains(CharSequence s) {
    2    return indexOf(s.toString()) > -1;
    3}
  • 根據給定的新的子字符串replacement,替換第一個匹配給定的正則表達式regex的子字符串,內部實則調用的是Matcher類的replaceFirst方法

    1 public String replaceFirst(String regex, String replacement) {
    2    return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    3}
  • 根據給定的新的子字符串replacement,替換全部匹配給定的正則表達式regex的子字符串,內部實則調用的是Matcher類的replaceAll方法

    1 public String replaceAll(String regex, String replacement) {
    2    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    3}
  • 更加通用的字符串替換方法,將匹配到的target字符序列所有替換爲replacement字符序列,內部調用的也是Matcher類的replaceAll方法

    1 public String replace(CharSequence target, CharSequence replacement) {
    2    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
    3            this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    4}
  • 去除字符串先後空格

     1    public String trim() {
    2    //當前字符串長度
    3    int len = value.length;
    4    //索引標誌位
    5    int st = 0;
    6    //當前字符串字符數組
    7    char[] val = value;    
    8    //從0開始遍歷循環,查找到空格的字符,則索引往前+1
    9    while ((st < len) && (val[st] <= ' ')) {
    10        st++;
    11    }
    12    //從字符串尾部開始遍歷循環,查找到空格字符,則長度日後-1
    13    while ((st < len) && (val[len - 1] <= ' ')) {
    14        len--;
    15    }
    16    //若是st索引大於0或者長度len小於總長度,則返回裁剪字符串st偏移量開始,裁剪len長度,不然直接返回當前字符串對象
    17    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    18}
  • 字符串轉化toString,繼承自Object重寫的方法,直接返回當前字符串對象

    1 public String toString() {
    2    return this;
    3}
  • 字符串轉化爲字符數組

    1  public char[] toCharArray() {
    2    //初始化字符串長度的字符數組
    3    char result[] = new char[value.length];
    4    //將字符串自己的字符數組拷貝至result[]並返回結果
    5    System.arraycopy(value, 0, result, 0, value.length);
    6    return result;
    7}

String 靜態方法

  • 不對外公開的內部靜態方法,從字符串source指定索引fromIndex開始遍歷,從偏移量sourceOffset,在原始字符串長度sourceCount範圍內查找目標字符串target中偏移量targetOffset開始,長度爲targetCount的字符串索引第一次出現的位置。

     1static int indexOf(char[] source, int sourceOffset, int sourceCount,
    2        char[] target, int targetOffset, int targetCount,
    3        int fromIndex)
     
    {
    4    //若是起始位置大於等於源字符串指定長度
    5    if (fromIndex >= sourceCount) {
    6        //若是目標字符串查找的長度爲0,則直接返回源字符串長度,不然返回-1表示未找到
    7        return (targetCount == 0 ? sourceCount : -1);
    8    }
    9    //起始位置小於0
    10    if (fromIndex < 0) {
    11        //重置爲0
    12        fromIndex = 0;
    13    }
    14    //目標字符串長度爲0,表明爲空字符串」「
    15    if (targetCount == 0) {
    16        //直接返回起始位置
    17        return fromIndex;
    18    }
    19    //目標字符串第一個字符
    20    char first = target[targetOffset];
    21    //從源字符偏移量開始,計算最大的遍歷次數
    22    int max = sourceOffset + (sourceCount - targetCount);
    23    //遍歷
    24    for (int i = sourceOffset + fromIndex; i <= max; i++) {
    25        //循環找出第一個字符
    26        if (source[i] != first) {
    27            while (++i <= max && source[i] != first);
    28        }
    29        //todo 這段暫時沒看明白 by zhangshaolin
    30        if (i <= max) {
    31            int j = i + 1;
    32            int end = j + targetCount - 1;
    33            for (int k = targetOffset + 1; j < end && source[j]
    34                    == target[k]; j++, k++);
    35            if (j == end) {
    36                /* Found whole string. */
    37                return i - sourceOffset;
    38            }
    39        }
    40    }
    41    //最終沒找到 則返回-1
    42    return -1;
    43}
  • 不對外公開的靜態方法,上述方法的另外一個重載形式,內部實則直接調用的上述方法,targetCount默認傳入target.value.length

    1   static int indexOf(char[] source, int sourceOffset, int sourceCount,
    2        String target, int fromIndex)
     
    {
    3    return indexOf(source, sourceOffset, sourceCount,
    4                   target.value, 0, target.value.length,
    5                   fromIndex);
    6}
  • 不對外公開的內部靜態方法,從字符串source指定索引fromIndex開始遍歷,從偏移量sourceOffset,在原始字符串長度sourceCount範圍內查找目標字符串target中偏移量targetOffset開始,長度爲targetCount的字符串索引第一次出現的位置。

     1 static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
    2        char[] target, int targetOffset, int targetCount,
    3        int fromIndex)
     
    {
    4    //源字符長度-目標字符長度,獲取起始位置
    5    int rightIndex = sourceCount - targetCount;
    6    //起始位置小於0,直接返回-1表示未找到目標
    7    if (fromIndex < 0) {
    8        return -1;
    9    }
    10    //若是形參起始位置大於計算的實際起始位置,則直接賦值給fromIndex
    11    if (fromIndex > rightIndex) {
    12        fromIndex = rightIndex;
    13    }
    14    //若是目標字符串長度爲0,表示爲空字符串,則直接返回起始位置
    15    if (targetCount == 0) {
    16        return fromIndex;
    17    }
    18    //獲取目標字符串最後一個索引位置
    19    int strLastIndex = targetOffset + targetCount - 1;
    20    //獲取目標字符串最後一個字符
    21    char strLastChar = target[strLastIndex];
    22    //獲取最小遍歷次數
    23    int min = sourceOffset + targetCount - 1;
    24    //最小遍歷次數+起始位置
    25    int i = min + fromIndex;
    26//循環查找最後一個字符
    27startSearchForLastChar:
    28    while (true) {
    29        while (i >= min && source[i] != strLastChar) {
    30            i--;
    31        }
    32        //若是i<min,則表明查找不到最後一個字符 返回-1
    33        if (i < min) {
    34            return -1;
    35        }
    36        //todo 這段邏輯暫時沒看明白 by zhangshaolin
    37        int j = i - 1;
    38        int start = j - (targetCount - 1);
    39        int k = strLastIndex - 1;
    40        while (j > start) {
    41            if (source[j--] != target[k--]) {
    42                i--;
    43                //找不到,繼續跳過外層循環
    44                continue startSearchForLastChar;
    45            }
    46        }
    47        return start - sourceOffset + 1;
    48    }
    49}
  • 不對外公開的靜態方法,上述方法的另外一個重載形式,內部實則直接調用的上述方法,targetCount默認傳入target.value.length

    1 static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
    2        String target, int fromIndex)
     
    {
    3    return lastIndexOf(source, sourceOffset, sourceCount,
    4                   target.value, 0, target.value.length,
    5                   fromIndex);
    6}
  • 將任意Object對象轉化爲字符串對象返回,內部實則也是調用的ObjecttoString方法,返回結果取決於該方法的具體實現

    1  public static String valueOf(Object obj) {
    2    //若是obj爲空,則返回"null",不然返回對象的toString返回的字符串結果
    3    return (obj == null) ? "null" : obj.toString();
    4}
  • 將字符數組轉化爲字符串對象返回,內部實際是用字符數組爲參數 從新 new 了一個新的字符串對象,並返回

    1public static String valueOf(char data[]) {
    2    return new String(data);
    3}
  • 將字符數組轉化爲字符串對象返回,同時指定索引偏移量offset,截取的長度count,內部實際是從新 new 了一個新的字符串對象,並返回

    1 public static String valueOf(char data[], int offset, int count) {
    2    return new String(data, offset, count);
    3}
  • 與上一個方法效果一致,只是方法名稱不一樣罷了

    1 public static String copyValueOf(char data[], int offset, int count) {
    2    return new String(data, offset, count);
    3}
  • valueOf(char data[])效果一致,只是方法名稱不一樣罷了

    1 public static String copyValueOf(char data[]) {
    2    return new String(data);
    3}
  • boolean類型數據轉化爲字符串對象返回

    1 public static String valueOf(boolean b) {
    2    //爲真 則返回"true" 不然返回"false"
    3    return b ? "true" : "false";
    4}
  • 將字符轉化爲字符串對象返回

    1 public static String valueOf(char c) {
    2    //初始化字符數組
    3    char data[] = {c};
    4    //從新new一個新的字符串對象返回
    5    return new String(data, true);
    6}
  • 將int數據轉換爲字符串對象返回,內部實際是調用的Integer.toString()方法

    1 public static String valueOf(int i) {
    2    return Integer.toString(i);
    3}
  • 將long數據轉換爲字符串對象返回,內部實際是調用的Long.toString()方法

    1 public static String valueOf(long l) {
    2    return Long.toString(l);
    3}
  • 將float數據轉換爲字符串對象返回,內部實際是調用的Float.toString()方法

    1 public static String valueOf(float f) {
    2    return Float.toString(f);
    3}
  • 將double數據轉換爲字符串對象返回,內部實際是調用的Double.toString()方法

    1 public static String valueOf(double d) {
    2    return Double.toString(d);
    3}

簡單總結

  • String源碼所有大體過了一遍以後,感慨 jdk 代碼設計的強大,幾天時間要徹底看懂是不容易的,目前也還有不少地方沒有徹底明白
  • 源碼並不可怕,可怕的是本身的畏懼心理,認爲源碼很難啃不動,其實否則,下定決心看下去,遇到不懂的能夠先pass,後面再回頭看可能就豁然開朗了。
  • String 內部本質就是操做字符數組 value[]
  • 由於本質就是操做字符數組,內部用到了大量的Arrays.copyOf,以及System.arraycopy方法

最後

看源碼不易,若是文中有錯誤之處,還請留言指出,一塊兒學習,一塊兒進步,謝謝!

更多原創文章會第一時間推送公衆號【張少林同窗】,歡迎關注!

原文出處:https://www.cnblogs.com/zhangshaolin/p/10239563.html

相關文章
相關標籤/搜索