Java源碼學習 -- java.lang.String


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      }
View Code

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     }
View Code

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     }
View Code

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     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM