1. 程式人生 > >String 原始碼淺析————終結篇

String 原始碼淺析————終結篇

寫在前面

說說這幾天看原始碼的感受吧,其實 jdk 中的原始碼設計是最值得進階學習的地方。我們在對 api 較為熟悉之後,完全可以去嘗試閱讀一些 jdk 原始碼,開啟 jdk 原始碼後,如果你英文能力稍微過得去,那麼原始碼有相當詳細的註釋告訴你 api 的含義,具體用法。假設平時在寫程式碼的過程中突然忘記了某個 api 的用法,那麼有些新手沒讀過原始碼的可能順手就開啟百度或者谷歌,搜尋 api 怎麼用?哈哈哈,面向谷歌程式設計,這樣的狀態可能會讓你一年的經驗重複n年, 如果是閱讀過原始碼,則直接進去看看原始碼英文註釋,回想一下原始碼的實現即可使用,而且看過原始碼後,裡面有些程式碼細節是可以在平時編碼的過程中直接借鑑的。

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

上一篇 String 原始碼淺析(一) 中已經對String前半部分原始碼做了解析,這篇把剩下的方法粗略的總結下...

String 成員方法

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

       public boolean equals(Object anObject) {
        //判斷形參跟當前字串物件地址是否相等,即是否為同一個物件,如果相等,則返回true
        if (this == anObject) {
            return true;
        }
        //如果形參為String型別物件
    if (anObject instanceof String) { //強轉為String型別物件 String anotherString = (String)anObject; //當前字串物件的字元陣列長度 int n = value.length; //如果當前字串物件的字元陣列長度等於形參字串字元陣列長度 if (n == anotherString.value.length) { //當前字串字元陣列 char v1[] = value; //形參字串字元陣列
    char v2[] = anotherString.value; //遍歷索引起始位置0 int i = 0; //遍歷當前字串字元陣列,每個索引位置的字元與形參字串索引位置字元比較,如果不相等則返回false while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } //以上條件都不滿足,最後返回false return false; } 複製程式碼
  • 傳入CharSequence介面形參,實際是與StringBuffer,StringBuilder比較是否相等,因為StringBuffer,StringBuilder都實現了CharSequence介面

    public boolean contentEquals(CharSequence cs) {
        //判斷形參是否是AbstractStringBuilder抽象類,實則因當傳入的是其子類:StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            //如果形參是StringBuffer型別物件
            if (cs instanceof StringBuffer) {
                //同步鎖,呼叫nonSyncContentEquals方法比較兩種是否相等
                synchronized(cs) {
                   return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                //如果形參物件是StringBuilder,則呼叫nonSyncContentEquals方法比較兩種是否相等
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // 如果形參是String物件,則直接呼叫equals方法返回
        if (cs instanceof String) {
            return equals(cs);
        }
        // 如果是其他的CharSequence實現類,則遍歷,一個個字元進行比較,找到一個字元不相等則直接返回false
        char v1[] = value;
        int n = v1.length;
        if (n != cs.length()) {
            return false;
        }
        for (int i = 0; i < n; i++) {
            if (v1[i] != cs.charAt(i)) {
                return false;
            }
        }
        //以上程式碼都不成立,走到最後直接返回true
        return true;
    }
    複製程式碼
  • 私有方法,非同步方式(執行緒不安全)比較與 AbstractStringBuilder 是否相等,實則是與其子類:StringBuffer, StringBuilder 比較大小,contentEquals(CharSequence cs)方法中核心比較程式碼就是呼叫該方法。

      private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
        //當前字串物件字元陣列
        char v1[] = value;
        //獲取形參字元陣列
        char v2[] = sb.getValue();
        //當前字串物件字元陣列長度
        int n = v1.length;
        //如果當前字串物件字元陣列長度不等於形參字元陣列長度,則直接返回false
        if (n != sb.length()) {
            return false;
        }
        //遍歷當前字串物件字元陣列,與形參字元陣列逐一比較字元,找到一個字元不相等,則直接返回false
        for (int i = 0; i < n; i++) {
            if (v1[i] != v2[i]) {
                return false;
            }
        }
        //以上條件都不成立,程式碼走到最後則直接返回true
        return true;
    }
    複製程式碼
  • 公有方法,比較與StringBuffer物件是否相等,內部實則直接呼叫的contentEquals(CharSequence cs)方法,可以說該方法是StringBuffer的特別版吧。

      public boolean contentEquals(StringBuffer sb) {
        return contentEquals((CharSequence)sb);
    }
    複製程式碼
  • 匹配兩個字串部分片段是否相等

      public boolean regionMatches(int toffset, String other, int ooffset,
            int len) {
        //當前字串字元陣列
        char ta[] = value;
        //當前字串開始比較的起始位置,即偏移量
        int to = toffset;
        //待比較的字串字元陣列
        char pa[] = other.value;
        //待比較的字串起始位置,即偏移量
        int po = ooffset;
        //索引檢查 1.偏移量小於0  2. 偏移量大於總長度-待比較的長度
        //以上兩種情況直接返回false
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        //遍歷,找出不相等的字元,則返回false
        while (len-- > 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        //不出意外,最終則返回true
        return true;
    }
    複製程式碼
  • 匹配兩個字串部分片段是否相等,同時判斷是否忽略大小寫

    public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        //當前字串字元陣列
        char ta[] = value;
        //當前字串開始比較的起始位置,即偏移量
        int to = toffset;
        //待比較的字串字元陣列
        char pa[] = other.value;
        //待比較的字串起始位置,即偏移量
        int po = ooffset;
        //索引檢查 1.偏移量小於0  2. 偏移量大於總長度-待比較的長度
        //以上兩種情況直接返回false
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)value.length - len)
                || (ooffset > (long)other.value.length - len)) {
            return false;
        }
        //遍歷檢查字元是否相等,相等則跳過
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            //如果字元不相等,且需要忽略大小寫比較
            if (ignoreCase) {
                //字元轉換為大寫
                char u1 = Character.toUpperCase(c1);
                char u2 = Character.toUpperCase(c2);
                //如果相等,則繼續跳過
                if (u1 == u2) {
                    continue;
                }
                //轉換為小寫進行比較,如果相等則繼續跳過
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                    continue;
                }
            }
            //否則發現不相等,則直接返回false
            return false;
        }
        //不出意外,最終返回true
        return true;
    }
    複製程式碼
  • 忽略大小寫比較字串大小

     public boolean equalsIgnoreCase(String anotherString) {
        //一句三目運算直接搞定
        //如果當前字串物件地址與形參字串相等,則返回true
        //否則判斷形參字串是否為空,形參字串長度是否與當前字串長度相等,直接呼叫regionMatches比較兩個字串所有字元是否相等,同時忽略大小寫比較
        //以上全部為true則相等
        return (this == anotherString) ? true
                : (anotherString != null)
                && (anotherString.value.length == value.length)
                && regionMatches(true, 0, anotherString, 0, value.length);
    }
    複製程式碼
  • 比較兩個字串是否相等,該方法實現自Comparable介面,返回 int 結果,等於0,則字串相等,小於0,則前者小於後者,大於0,則前者大於後者

      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;
        //索引位置0開始
        int k = 0;
        //遍歷較小的字元陣列
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            //如果字元不相等
            if (c1 != c2) {
                //返回字元之差
                return c1 - c2;
            }
            k++;
        }
        //如果字元都相等,則返回長度之差
        return len1 - len2;
    }
    複製程式碼
  • 使用預設比較器不區分大小寫比較兩個字串大小

    //初始化預設的比較器
    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    //預設的比較器,不區分大小寫                          
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;
    
        public int compare(String s1, String s2) {
            //第一個字串長度
            int n1 = s1.length();
            //第二個字串長度
            int n2 = s2.length();
            //取小
            int min = Math.min(n1, n2);
            //遍歷較小的字串
            for (int i = 0; i < min; i++) {
                //獲取指定索引字元
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                //如果字元不相等
                if (c1 != c2) {
                    //轉化為大寫
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    //轉化為大寫後比較,不相等
                    if (c1 != c2) {
                        //轉化為小寫繼續比較
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        //轉化為小寫字元,不相等
                        if (c1 != c2) {
                            //直接返回字元之差
                            return c1 - c2;
                        }
                    }
                }
            }
            //不出意外,最終返回長度之差
            return n1 - n2;
        }
    
        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }
    
    //內部直接呼叫預設比較器的compare方法
    public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }
    複製程式碼
  • 從指定偏移量開始,判斷是否以指定字串開頭

     public boolean startsWith(String prefix, int toffset) {
        //當前字串字元陣列
        char ta[] = value;
        //偏移量
        int to = toffset;
        //指定字串字首字元陣列
        char pa[] = prefix.value;
        //索引位置0開始
        int po = 0;
        //指定字串字首陣列長度
        int pc = prefix.value.length;
        //偏移量小於0 或者 //偏移量大於總長度-字串字首長度,則直接返回false
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        //遍歷字首字串
        while (--pc >= 0) {
            //從偏移量開始檢索,找到字元不相等,則返回false
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        //不出意外,最後則返回true
        return true;
    }
    複製程式碼
  • 從字串開頭,判斷是否以指定字串開頭

     public boolean startsWith(String prefix) {
        //直接呼叫startsWith過載方法,偏移量為0
        return startsWith(prefix, 0);
    }
    複製程式碼
  • 判斷是否以指定字串結尾,內部直接呼叫的 startsWith 方法,偏移量為總字串長度-字尾字串長度即可。

    public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length);
    }
    複製程式碼
  • 從指定偏移量開始,搜尋指定字元在字串中第一次出現的索引位置

     public int indexOf(int ch, int fromIndex) {
        //當前字串字元陣列長度
        final int max = value.length;
        //如果偏移量小於0,則重置為0
        if (fromIndex < 0) {
            fromIndex = 0;
        } else if (fromIndex >= max) {
            //偏移量大於總長度,則返回-1,意味著找不到指定字元
            return -1;
        }
    
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            //當前字串字元陣列
            final char[] value = this.value;
            //從偏移量位置開始遍歷
            for (int i = fromIndex; i < max; i++) {
                //找到相等的字元,則返回索引
                if (value[i] == ch) {
                    return i;
                }
            }
            //找不到則返回-1
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }
    複製程式碼
  • 查詢指定字元在字串中第一次出現的索引位置,從偏移量0開始遍歷查詢

     public int indexOf(int ch) {
        return indexOf(ch, 0);
    }
    複製程式碼
  • 查詢指定字元在字串中最後一次出現的索引位置,從指定偏移量開始遍歷

      public int lastIndexOf(int ch, int fromIndex) {
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            //當前字串字元陣列
            final char[] value = this.value;
            //偏移量與字串最後的位置取小
            int i = Math.min(fromIndex, value.length - 1);
            //從後遍歷字元陣列
            for (; i >= 0; i--) {
                //找到相等的字元,返回索引
                if (value[i] == ch) {
                    return i;
                }
            }
            //找不到則返回-1
            return -1;
        } else {
            return lastIndexOfSupplementary(ch, fromIndex);
        }
    }
    複製程式碼
  • 查詢指定字元在字串中最後一次出現的索引位置,從字串最後一個索引位置開始遍歷查詢

     public int lastIndexOf(int ch) {
        return lastIndexOf(ch, value.length - 1);
    }
    複製程式碼
  • 從指定位置開始,查詢字串在源字串中第一次出現的的索引位置,內部實則直接呼叫的indexOf內部靜態方法

      public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    複製程式碼
  • 查詢字串在源字串中第一次出現的的索引位置,內部實則直接呼叫的上述indexOf方法,fromIndex預設從0開始

     public int indexOf(String str) {
        return indexOf(str, 0);
    }
    複製程式碼
  • 從指定位置開始,查詢字串在源字串中最後一次出現的的索引位置,內部實則直接呼叫的lastIndexOf內部靜態方法

     public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    複製程式碼
  • 查詢字串在源字串中最後一次出現的的索引位置,內部實則直接呼叫的上述lastIndexOf方法,fromIndex預設從value.length開始

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

        public String substring(int beginIndex, int endIndex) {
        //起始位置小於0,丟擲索引越界異常
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //結束位置大於字串總長度,則丟擲索引越界異常
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        //待擷取的字串長度
        int subLen = endIndex - beginIndex;
        //待擷取的字串長度小於0,則丟擲索引越界異常
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //三目判斷 起始位置等於0,並且結束位置等於字串長度,則表示為擷取總長度,返回當前字串物件
        //否則重新new一個字串例項,從beginIndex開始,擷取subLen長度
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
    複製程式碼
  • 從起始位置beginIndex開始擷取源字串到結尾,返回子字串

     public String substring(int beginIndex) {
        //起始位置小於0,丟擲索引越界異常
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //待擷取的字串長度
        int subLen = value.length - beginIndex;
        //待擷取的字串長度小於0,則丟擲索引越界異常
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //三目判斷 起始位置等於0,則表示為擷取總長度,返回當前字串物件,否則重新new一個新的字串例項,從beginIndex開始,擷取subLen長度
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
    複製程式碼
  • 按照指定區間裁剪字串,返回CharSequence介面,beginIndex起始位置(包含),endIndex結束位置(不包含),內部實則直接呼叫的substring方法,只是返回的是最上層介面罷了

     public CharSequence subSequence(int beginIndex, int endIndex) {
        return this.substring(beginIndex, endIndex);
    }
    複製程式碼
  • 字串拼接,將目標字串拼接在尾部,返回新的字串

      public String concat(String str) {
        //待拼接的字串長度
        int otherLen = str.length();
        //如果待拼接的字串長度等於0,則直接返回當前字串物件
        if (otherLen == 0) {
            return this;
        }
        //當前字串長度
        int len = value.length;
        //將當前字串字元陣列拷貝到新的字元陣列buf[]中,長度擴容至len + otherLen
        char buf[] = Arrays.copyOf(value, len + otherLen);
        //將待拼接的字元陣列拷貝至buf[]中,從len開始,理論上這部操作完之後,字元陣列已經拼接成功了
        str.getChars(buf, len);
        //利用最新的字元陣列,重新new一個新的字串例項返回
        return new String(buf, true);
    }
    複製程式碼
  • 將字串中指定字元oldChar替換為新的字元newChar

      public String replace(char oldChar, char newChar) {
        //如果舊的字元跟新的字元不相等,才執行替換邏輯,否則直接返回當前字串物件
        if (oldChar != newChar) {
            //當前字串長度
            int len = value.length;
            //索引從-1開始
            int i = -1;
            //當前字串字元陣列
            char[] val = value;
            //遍歷當前字元陣列,從0開始,因為++i之後等於0
            while (++i < len) {
                //找到與oldChar相等的字元,則中斷迴圈
                if (val[i] == oldChar) {
                    break;
                }
            }
            //如果oldChar索引位置i小於當前字元陣列長度,意味著在當前字串中找到了oldChar
            if (i < len) {
                //初始化字串長度的字元陣列
                char buf[] = new char[len];
                //從0開始遍歷到oldChar所在位置,將字元放入buf
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                //從oldChar索引位置i開始遍歷到字串結尾
                while (i < len) {
                    //當前字元
                    char c = val[i];
                    //如果當前字元等於oldChar,則newChar賦值給buf[i],否則不變
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                //最後根據buf陣列重新new一個新的字串例項返回
                return new String(buf, true);
            }
        }
        return this;
    }
    複製程式碼
  • 根據字串正則regex匹配字串,返回boolean,內部實則是呼叫正則匹配的api方法

    public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }
    複製程式碼
  • 判斷字串是否包含指定字元序列CharSequence,內部實則是呼叫indexOf方法,判斷返回結果是否大於-1

     public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }
    複製程式碼
  • 根據給定的新的子字串replacement,替換第一個匹配給定的正則表示式regex的子字串,內部實則呼叫的是Matcher類的replaceFirst方法

     public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }
    複製程式碼
  • 根據給定的新的子字串replacement,替換所有匹配給定的正則表示式regex的子字串,內部實則呼叫的是Matcher類的replaceAll方法

     public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
    複製程式碼
  • 更加通用的字串替換方法,將匹配到的target字元序列全部替換為replacement字元序列,內部呼叫的也是Matcher類的replaceAll方法

     public String replace(CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }
    複製程式碼
  • 去除字串前後空格

        public String trim() {
        //當前字串長度
        int len = value.length;
        //索引標誌位
        int st = 0;
        //當前字串字元陣列
        char[] val = value;    
        //從0開始遍歷迴圈,查詢到空格的字元,則索引往前+1
        while ((st < len) && (val[st] <= ' ')) {
            st++;
        }
        //從字串尾部開始遍歷迴圈,查詢到空格字元,則長度往後-1
        while ((st < len) && (val[len - 1] <= ' ')) {
            len--;
        }
        //如果st索引大於0或者長度len小於總長度,則返回裁剪字串st偏移量開始,裁剪len長度,否則直接返回當前字串物件
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }
    複製程式碼
  • 字串轉化toString,繼承自Object重寫的方法,直接返回當前字串物件

     public String toString() {
        return this;
    }
    複製程式碼
  • 字串轉化為字元陣列

      public char[] toCharArray() {
        //初始化字串長度的字元陣列
        char result[] = new char[value.length];
        //將字串本身的字元陣列拷貝至result[]並返回結果
        System.arraycopy(value, 0, result, 0, value.length);
        return result;
    }
    複製程式碼

String 靜態方法

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

    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        //如果起始位置大於等於源字串指定長度
        if (fromIndex >= sourceCount) {
            //如果目標字串查詢的長度為0,則直接返回源字串長度,否則返回-1表示未找到
            return (targetCount == 0 ? sourceCount : -1);
        }
        //起始位置小於0
        if (fromIndex < 0) {
            //重置為0
            fromIndex = 0;
        }
        //目標字串長度為0,代表為空字串”“
        if (targetCount == 0) {
            //直接返回起始位置
            return fromIndex;
        }
        //目標字串第一個字元
        char first = target[targetOffset];
        //從源字元偏移量開始,計算最大的遍歷次數
        int max = sourceOffset + (sourceCount - targetCount);
        
        //遍歷
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            //迴圈找出第一個字元
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }
            
            //todo 這段暫時沒看明白 by zhangshaolin
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
    
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        //最終沒找到 則返回-1
        return -1;
    }
    複製程式碼
  • 不對外公開的靜態方法,上述方法的另一個過載形式,內部實則直接呼叫的上述方法,targetCount預設傳入target.value.length

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

     static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        
        //源字元長度-目標字元長度,獲取起始位置
        int rightIndex = sourceCount - targetCount;
        //起始位置小於0,直接返回-1表示未找到目標
        if (fromIndex < 0) {
            return -1;
        }
        //如果形參起始位置大於計算的實際起始位置,則直接賦值給fromIndex
        if (fromIndex > rightIndex) {
            fromIndex = rightIndex;
        }
        //如果目標字串長度為0,表示為空字串,則直接返回起始位置
        if (targetCount == 0) {
            return fromIndex;
        }
        //獲取目標字串最後一個索引位置
        int strLastIndex = targetOffset + targetCount - 1;
        //獲取目標字串最後一個字元
        char strLastChar = target[strLastIndex];
        //獲取最小遍歷次數
        int min = sourceOffset + targetCount - 1;
        //最小遍歷次數+起始位置
        int i = min + fromIndex;
    
    //迴圈查詢最後一個字元
    startSearchForLastChar:
        while (true) {
            while (i >= min && source[i] != strLastChar) {
                i--;
            }
            //如果i<min,則代表查詢不到最後一個字元 返回-1
            if (i < min) {
                return -1;
            }
            //todo 這段邏輯暫時沒看明白 by zhangshaolin
            int j = i - 1;
            int start = j - (targetCount - 1);
            int k = strLastIndex - 1;
    
            while (j > start) {
                if (source[j--] != target[k--]) {
                    i--;
                    //找不到,繼續跳過外層迴圈
                    continue startSearchForLastChar;
                }
            }
            return start - sourceOffset + 1;
        }
    }
    複製程式碼
  • 不對外公開的靜態方法,上述方法的另一個過載形式,內部實則直接呼叫的上述方法,targetCount預設傳入target.value.length

     static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
            String target, int fromIndex) {
        return lastIndexOf(source, sourceOffset, sourceCount,
                       target.value, 0, target.value.length,
                       fromIndex);
    }
    複製程式碼
  • 將任意Object物件轉化為字串物件返回,內部實則也是呼叫的ObjecttoString方法,返回結果取決於該方法的具體實現

      public static String valueOf(Object obj) {
        //如果obj為空,則返回"null",否則返回物件的toString返回的字串結果
        return (obj == null) ? "null" : obj.toString();
    }
    複製程式碼
  • 將字元陣列轉化為字串物件返回,內部實際是用字元陣列為引數 重新 new 了一個新的字串物件,並返回

    public static String valueOf(char data[]) {
        return new String(data);
    }
    複製程式碼
  • 將字元陣列轉化為字串物件返回,同時指定索引偏移量offset,擷取的長度count,內部實際是重新 new 了一個新的字串物件,並返回

     public static String valueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }
    複製程式碼
  • 與上一個方法效果一致,只是方法名稱不同罷了

     public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }
    複製程式碼
  • valueOf(char data[])效果一致,只是方法名稱不同罷了

     public static String copyValueOf(char data[]) {
        return new String(data);
    }
    複製程式碼
  • boolean型別資料轉化為字串物件返回

     public static String valueOf(boolean b) {
        //為真 則返回"true" 否則返回"false"
        return b ? "true" : "false";
    }
    複製程式碼
  • 將字元轉化為字串物件返回

     public static String valueOf(char c) {
        //初始化字元陣列
        char data[] = {c};
        //重新new一個新的字串物件返回
        return new String(data, true);
    }
    複製程式碼
  • 將int資料轉換為字串物件返回,內部實際是呼叫的Integer.toString()方法

     public static String valueOf(int i) {
        return Integer.toString(i);
    }
    複製程式碼
  • 將long資料轉換為字串物件返回,內部實際是呼叫的Long.toString()方法

    
                
               

    相關推薦

    String 原始碼淺析————終結

    寫在前面 說說這幾天看原始碼的感受吧,其實 jdk 中的原始碼設計是最值得進階學習的地方。我們在對 api 較為熟悉之後,完全可以去嘗試閱讀一些 jdk 原始碼,開啟 jdk 原始碼後,如果你英文能力稍微過得去,那麼原始碼有相當詳細的註釋告訴你 api 的含義,具體用法。假設平時在寫程式碼

    String 原始碼淺析

    引言 從一段程式碼說起: public void stringTest(){     String a = "a"+"b"+1;     String b = "ab1";     System.out.println(a == b); } 大家猜一猜結果如何?如果你的結

    Android應用Preference相關及原始碼淺析(SharePreferences)

    1 前言 在我們開發Android過程中資料的儲存會有很多種解決方案,譬如常見的檔案儲存、資料庫儲存、網路雲端儲存等,但是Android系統為咱們提供了更加方便的一種資料儲存方式,那就是SharePreference資料儲存。其實質也就是檔案儲存,只不過是符合

    Java String 原始碼淺析

    String表示字串,Java中所有字串的字面值都是String類的例項,例如“ABC”。字串是常量,在定義之後不能被改變,字串緩衝區支援可變的字串。因為 String 物件是不可變的,所以可以共享它們。例如: String str = "abc"; 相當於 char

    String原始碼淺析

    如果問你,開發過程中用的最多的類是哪個?你可能回答是`HashMap`,一個原因就是HashMap的使用量的確很多,還有就是HashMap的內容在面試中經常被問起。 但是在開發過程中使用最多的類其實並不是HashMap類,而是“默默無聞”的String類。假如現在問你String類是怎麼實現的?這個類為什麼

    rxJava和rxAndroid原始碼解析系列四之subscribeOn和observeOn的理解(學習終結)

    本篇文章主要解決subscribeOn和observeOn這兩個方法為什麼subscribeOn只有一次有效果,observeOn切換多次回撥的都有效果。 不知道朋友有沒有看過rxandroid的原始碼,如果看過的話,就會迎刃而解,沒什麼疑慮啦。沒看過原始碼的朋友,可以看看我這個系列的前幾篇文章

    原始碼分析String原始碼分析二

        前面已經分析過String原始碼為什麼是不可變的,同時通過我們常用的String的相關的類StringBuffer和StringBuilder,我們可以發現String類中欄位名被定義為了final型別,這樣的話將只能被賦值一次。接下來,繼續看String原始碼實現的

    原始碼分析String原始碼分析三

        上期已經討論了比較器的相關的問題。同時也提出問題明明父類已經實現了某個介面,子類為什麼還是要實現同樣的介面呢。這究竟有什麼意義呢。通過使用度孃的多次探究之後最終我還是沒有發現說它有什麼特別的含義。我認為的最大的含義就是告訴使用者這個類實現了這樣的一個介面。方便使用者進

    開發人員學Linux之終結:大型系統開發經驗談

    bug 架構 版本管理 質量 管控 1.前言這篇文章來源於我的一個ppt,而這個ppt是源於一個朋友的一次邀請,朋友邀請我為一個公司做一堂大約2小時的技術講座,我選定的方向是如何開發一個大型系統,在這裏我對大型系統的定義為日均PV在千萬級以上,而京東和淘寶這類則屬於巨型系統了。因此在本篇中

    python基礎19 -------面向對象終結(介紹python對象中各種內置命令)

    .com 介紹 類和對象 python false 指定 事物 width images 一、isinstance()和issubclass()命令   1、isinstance(對象,類型)     用來判定該對象是不是此類型或者說是該對象是不是此類的對象,返回結果為Tr

    python基礎27 -----python進程終結-----IO模型

    非阻塞 緩存 代碼原理 linux系統 並不會 async process 而不是 拷貝數據 一、IO模型   1、IO模型分類     1.阻塞IO--------blocking IO     2.非阻塞IO------nonblocking IO     3. 多路復

    第十三天內容《基礎交換十三》小牛配置思路 終結

    cisco 交換機 路由器 基礎交換 深圳雲計算王森 小牛配置思路: 1、配置終端主機 確保為 DHCP 客戶端; 2、交換網絡互通 vlan - 創建 VLAN :10,20,30,40,50,60 - VLAN 成

    linux系統學習第十八天《搭建一鍵裝機平臺》終結

    linux工程師技術 linux管理員技術 linux雲計算運維 深圳雲計算王森 雲計算運維工程師 在真機上,利用clone-vm7新建一臺虛擬機,名字:PXE-Server 1.設置防火墻為trusted 2.當前及永久關閉SELinux 3.配置IP地址:192.

    LAMP平臺搭建-PHP終結

    PHP LAMP PHP知識部分LAMP平臺的構成組件:1、Linux操作系統,Linux操作系統是整個LAMP架構的基礎部分,提供用於支撐Web站點的操作系統,為其他的組件提供了更好的穩定性、兼容性2、Apache網站服務器,作為LAMP架構的前端,功能強大、穩定性良好3、MySQL數據庫服務器,為

    MySQL 數據庫規範--調優(終結)

    linu 默認 展示 -i 慢查詢日誌 整體 核數 -h 表示 前言 這篇是MySQL 數據庫規範的最後一篇--調優篇,旨在提供我們發現系統性能變弱、MySQL系統參數調優,SQL腳本出現問題的精準定位與調優方法。 目錄 1.MySQL 調優金字塔理論 2.M

    跟我一起學docker(18)--持續集成(初級終結

    any 啟動 任務 -a https 開發 封裝 p s load 如何持續集成imageimage0 :開發人員提交代碼到github1 :觸發jenkins操作2 :jenkins將代碼編譯、驗證3 :將代碼封裝在docker鏡像並上傳至docker倉庫4 :jenki

    終結】不要再問我程序員該如何提高了……

    互聯 還要 了解 但是 這就是 指揮 容易 程序 自己 已經工作了的程序員該如何提高自己?我看到過很多說法,包括但不限於: 多讀書,然後各種書單,技術的、管理的,情商的、智商的,文學的、藝術的…… 鍛煉健身,身體是革命的本錢嘛! 寫博客,這個@dudu應該最喜歡了 多交朋

    js 閉包,作用域,this 終結(轉)

    ~~ fun 點擊 結束 終結篇 nbsp 重要 它的 定義變量 之前有寫過閉包,作用域,this方面的文章,但現在想想當時寫的真是廢話太多了,以至於繞來繞去的,讓新手反而更難理解了,所以就有了此篇文章,也好和閉包,作用域,this告一段落。   第一個問

    Jvm垃圾回收器(終結

    掃描 star rem 提前 判斷 清除 png 重要 處的 Jvm垃圾回收目前就準備了這三篇博文進行整理,在寫博文的過程中我也是邊看邊記載的,我覺得這種學習方式更容易讓人記住,不會輕易忘記。以前的學習模式都是看PDF文檔、看書等,但是有個缺點就是當時記住了過段時間就會忘記

    重新去認識HashMap(Java8原始碼淺析

    加入新公司後一直忙於專案,瘋狂加班,斷更了N個月,一直沒時間去管理自己所學習的新的知識(說白了就是懶。。。),前些天在頭條上看到了一篇關於jdk5,6,7,8,9的一些區別的文章,雖然有所瞭解,但由於自己的專案中用的依舊還是1.6,因此並沒有很多機會去了解一些新版本的一些特性(說白了還是