說說這幾天看源碼的感覺吧,其實 jdk
中的源碼設計是最值得進階學習的地方。咱們在對 api
較爲熟悉以後,徹底能夠去嘗試閱讀一些 jdk
源碼,打開 jdk
源碼後,若是你英文能力稍微過得去,那麼源碼有至關詳細的註釋告訴你 api
的含義,具體用法。假設平時在寫代碼的過程當中忽然忘記了某個 api
的用法,那麼有些新手沒讀過源碼的可能順手就打開百度或者谷歌,搜索 api 怎麼用?哈哈哈,面向谷歌編程,這樣的狀態可能會讓你一年的經驗重複n
年, 若是是閱讀過源碼,則直接進去看看源碼英文註釋,回想一下源碼的實現便可使用,並且看過源碼後,裏面有些代碼細節是能夠在平時編碼的過程當中直接借鑑的。html
廢話有點多啦~~滴滴滴,上車了。。。java
上一篇 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(true, 0, 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}
不對外公開的內部靜態方法,從字符串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
對象轉化爲字符串對象返回,內部實則也是調用的Object
的toString
方法,返回結果取決於該方法的具體實現
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