java.lang.String是使用頻率非常高的類。要想更好的使用java.lang.String類,了解其源代碼實現是非常有必要的。由java.lang.String,自然聯想到java.lang.StringBuffer和java.lang.StringBuilder,下篇文章再來研究java.lang.StringBuffer和java.lang.StringBuilder。
重要屬性
java.lang.String對象中字符串主要是以字符數組的形式存儲。當調用對象方法獲取字符串長度時,直接返回數組長度。判斷字符串是否為空isEmpty()時,也直接檢查數組長度是否為0。其部分發生代碼如下所示:
1 /** The value is used for character storage. */ 2 private final char value[]; 3 4 /** Cache the hash code for the string */ 5 private int hash; // Default to 0
value:存儲字符串的字符數組。該數組為final變量,一旦賦值,將不會更改。
hash:該String對象的哈希值。
構造方法
java.lang.String對象構造方法比較多,列舉如下:
1 public String() 2 public String(String original) 3 public String(char value[]) 4 public String(char value[], int offset, int count) 5 public String(int[] codePoints, int offset, int count) 6 @Deprecated 7 public String(byte ascii[], int hibyte, int offset, int count) 8 @Deprecated 9 public String(byte ascii[], int hibyte) 10 public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException 11 public String(byte bytes[], int offset, int length, Charset charset) 12 public String(byte bytes[], String charsetName) throws UnsupportedEncodingException 13 public String(byte bytes[], Charset charset) 14 public String(byte bytes[], int offset, int length) 15 public String(byte bytes[]) 16 public String(StringBuffer buffer) 17 public String(StringBuilder builder)
在 public String(StringBuffer buffer) 中,傳入形參為StringBuffer,StringBuffer為線程安全類。則在此構造方法內部進行了synchronized關鍵字鎖同步。代碼如下:
1 public String(StringBuffer buffer) { 2 synchronized(buffer) { 3 this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); 4 } 5 }
在 public String(StringBuilder builder) 中,傳入形參為StringBuilder,StringBuilder為非線程安全類。則在此構造方法內部內部未做同步處理,對比 public String(StringBuffer buffer) 。代碼如下:
1 public String(StringBuilder builder) { 2 this.value = Arrays.copyOf(builder.getValue(), builder.length()); 3 }
常用方法
java.lang.String對象中封裝方法非常多,僅針對常用方法源代碼進行分析。如:equals(),replace(), indexOf(),startsWith(),compareTo(),regionMathes(),hashCode()。
public boolean equals(Object anObject)
用於比較兩對象存儲內容是否相同。采用比較巧妙的方式進行排除比較:(1)先“==”比較兩對象是否是同一對象,若是,直接返回true, 否則進一步判斷;(2)判斷待比較對象類型是否是java.lang.String,若不是,直接返回false,否則進一步判斷;(3)判斷兩字符串長度是否相等,若不是直接返回false,否則進一步判斷;(4)從字符數組中第一個字符開始,依次進行比較,一旦發現不相同字符直接返回false,若所在字符均相同則返回true。對字符數組中字符依次進行比較是一件非常耗時的操作,將此操作放在最后執行,先利用其它條件進行對其進行判斷。比較巧妙!
1 public boolean equals(Object anObject) { 2 if (this == anObject) { 3 return true; 4 } 5 if (anObject instanceof String) { 6 String anotherString = (String)anObject; 7 int n = value.length; 8 if (n == anotherString.value.length) { 9 char v1[] = value; 10 char v2[] = anotherString.value; 11 int i = 0; 12 while (n-- != 0) { 13 if (v1[i] != v2[i]) 14 return false; 15 i++; 16 } 17 return true; 18 } 19 } 20 return false; 21 }
public String replace(char oldChar, char newChar)
將字符串中指定字符替換為新的字符。(1)先判斷待替換字符和新字符是否相同,若相同,則直接返回原字符串,若不同,則繼續執行;(2)找出第一次出現待替換字符位置i,創建新的等長字符數組,將該位置之前的字符依次放入新的字符數組中;(3)從位置i處依次遍歷比較原字符數組中字符是否是待替換字符,若是,則將新字符放入新字符數組對應位置,若不是,則將原字符數組中字符放入對應位置。巧妙做了一個小優化,直接找出第一次出現待替換字符的位置,再從此處開始遍歷,提高效率。
1 public String replace(char oldChar, char newChar) { 2 if (oldChar != newChar) { 3 int len = value.length; 4 int i = -1; 5 char[] val = value; /* avoid getfield opcode */ 6 7 while (++i < len) { 8 if (val[i] == oldChar) { 9 break; 10 } 11 } 12 if (i < len) { 13 char buf[] = new char[len]; 14 for (int j = 0; j < i; j++) { 15 buf[j] = val[j]; 16 } 17 while (i < len) { 18 char c = val[i]; 19 buf[i] = (c == oldChar) ? newChar : c; 20 i++; 21 } 22 return new String(buf, true); 23 } 24 } 25 return this; 26 }
public String replace(CharSequence target, CharSequence replacement)
該方法是我們通常意義所用到的 public String replace(String target, String replacement) ,java.lang.String實現了java.lang.CharSequence接口。方法內部調用正則表達式匹配替換來實現。
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 }
public int indexOf(String str)
該方法是找出目標字符串是第一次出現指定子字符串的位置,若不存在,則返回-1,若存在,則返回位置坐標。具體實現是調用 static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) 方法。先對目標字符串中出現子字符串的位置可能范圍,然后在此范圍中遍歷找出與子字符串第一個字符相同的位置,並對后面字符進行比較分析。

1 /** 2 * Returns the index within this string of the first occurrence of the 3 * specified substring. 4 */ 5 public int indexOf(String str) { 6 return indexOf(str, 0); 7 } 8 9 /** 10 * Returns the index within this string of the first occurrence of the 11 * specified substring, starting at the specified index. 12 */ 13 public int indexOf(String str, int fromIndex) { 14 return indexOf(value, 0, value.length, 15 str.value, 0, str.value.length, fromIndex); 16 } 17 18 /** 19 * Code shared by String and StringBuffer to do searches. The 20 * source is the character array being searched, and the target 21 * is the string being searched for. 22 * 23 * @param source the characters being searched. 24 * @param sourceOffset offset of the source string. 25 * @param sourceCount count of the source string. 26 * @param target the characters being searched for. 27 * @param targetOffset offset of the target string. 28 * @param targetCount count of the target string. 29 * @param fromIndex the index to begin searching from. 30 */ 31 static int indexOf(char[] source, int sourceOffset, int sourceCount, 32 char[] target, int targetOffset, int targetCount, 33 int fromIndex) { 34 if (fromIndex >= sourceCount) { 35 return (targetCount == 0 ? sourceCount : -1); 36 } 37 if (fromIndex < 0) { 38 fromIndex = 0; 39 } 40 if (targetCount == 0) { 41 return fromIndex; 42 } 43 44 char first = target[targetOffset]; 45 int max = sourceOffset + (sourceCount - targetCount); 46 47 for (int i = sourceOffset + fromIndex; i <= max; i++) { 48 /* Look for first character. */ 49 if (source[i] != first) { 50 while (++i <= max && source[i] != first); 51 } 52 53 /* Found first character, now look at the rest of v2 */ 54 if (i <= max) { 55 int j = i + 1; 56 int end = j + targetCount - 1; 57 for (int k = targetOffset + 1; j < end && source[j] 58 == target[k]; j++, k++); 59 60 if (j == end) { 61 /* Found whole string. */ 62 return i - sourceOffset; 63 } 64 } 65 } 66 return -1; 67 }
public int compareTo(String anotherString)
該方法是對字符串集合進行排序的基礎,通過此方法可比較兩字符串大小,原理很簡單,源代碼如下:

1 public int compareTo(String anotherString) { 2 int len1 = value.length; 3 int len2 = anotherString.value.length; 4 int lim = Math.min(len1, len2); 5 char v1[] = value; 6 char v2[] = anotherString.value; 7 8 int k = 0; 9 while (k < lim) { 10 char c1 = v1[k]; 11 char c2 = v2[k]; 12 if (c1 != c2) { 13 return c1 - c2; 14 } 15 k++; 16 } 17 return len1 - len2; 18 }
public boolean startsWith(String prefix)
判斷目標字符串是否以指定字符子串開關,該方法內部是調用 public boolean startsWith(String prefix, int toffset) 方法實現,原理很簡單,代碼如下:

1 /** 2 * Tests if this string starts with the specified prefix. 3 * 4 * @param prefix the prefix. 5 */ 6 public boolean startsWith(String prefix) { 7 return startsWith(prefix, 0); 8 }
public int hashCode()
其hashCode()代碼如下:
1 public int hashCode() { 2 int h = hash; 3 if (h == 0 && value.length > 0) { 4 char val[] = value; 5 6 for (int i = 0; i < value.length; i++) { 7 h = 31 * h + val[i]; 8 } 9 hash = h; 10 } 11 return h; 12 }