本博文參照API文檔以及源碼進行閱讀,源碼參考JDK1.8。java
java.lang.String public final class String extends Object implements Serializable, Comparable<String>, CharSequence
JDK1.0出現。數組
上面由API提供的描述,能夠看出,String是一個最終類,繼承了Object類,實現了序列化接口和排序接口以及char可讀序列接口。能夠得出如下幾個特色。緩存
如下爲String類中提供的屬性字段。安全
//存儲結構,String類型其實就是使用char數組在內存中進行存儲的。也能夠說String是基於char數組實現的。 private final char value[]; //緩存hashcode,默認值爲0 private int hash; //序列化版本號 private static final long serialVersionUID = -6849794470754667710L; //序列化對象文件 private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; //一個對 String 對象進行排序的 Comparator,做用與 compareToIgnoreCase 相同 public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
如下是String提供全部構造方法。函數
//默認構造,能夠看出,確實是基於char數組進行存儲的。 public String() { this.value = new char[0]; } //這個構造是一個參數,直接給兩個屬性賦值 public String(String original) { this.value = original.value; this.hash = original.hash; } //將整個char數組轉變成字符串 public String(char value[]) { //這裏面藉助的是數組的複製,來進行賦值。 this.value = Arrays.copyOf(value, value.length); } //將char數組的一部分轉變成字符串 //value:要轉變的數組;offset:開始的下標;count:轉變的數量。 public String(char value[], int offset, int count) { //判斷下標是不是異常值 if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } //判斷數量是不是異常值。 if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // 判斷下標和數量組合是否會越界 if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } //利用數組複製,進行賦值。 this.value = Arrays.copyOfRange(value, offset, offset+count); } //這個方法和上述方法同樣,只是換了類型,將char類型的數組換成了int類型的數組。 public String(int[] codePoints, int offset, int count) { //判斷開始位置是否異常。 if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } //判斷數量是否異常。 if (count < 0) { throw new StringIndexOutOfBoundsException(count); } //判斷下標和數量組合是否會越界。 if (offset > codePoints.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } //聲明一個數組最大的標誌位 final int end = offset + count; // 聲明一個數量,等於count,用於聲明新數組使用。 int n = count; for (int i = offset; i < end; i++) { //獲取數組中當前位的元素 int c = codePoints[i]; //判斷元素是否在char字符代碼點中 if (Character.isBmpCodePoint(c)) //若是在就繼續代碼邏輯 continue; //判斷此元素的代碼點是否有效 else if (Character.isValidCodePoint(c)) //記錄加一 n++; //其餘狀況則拋出異常 else throw new IllegalArgumentException(Integer.toString(c)); } // 聲明char數組,用來接收轉換過的字符串 final char[] v = new char[n]; //循環遍歷int數組進行賦值 for (int i = offset, j = 0; i < end; i++, j++) { int c = codePoints[i]; if (Character.isBmpCodePoint(c)) v[j] = (char)c; else Character.toSurrogates(c, v, j++); } //直接將v數組賦值給value屬性 this.value = v; } //此構造方法已通過時 @Deprecated //ascii[]:字節數組;hibyte:每一個16位Unicode代碼單元的前8位;offset:開始的位置;count:個數。 public String(byte ascii[], int hibyte, int offset, int count) { //檢查邊界,此方法,在String內部聲明,在API文檔中看不到,只在源碼中可以看到 checkBounds(ascii, offset, count); //建立一個接受值的char數組,大小爲count。 char value[] = new char[count]; // if (hibyte == 0) { for (int i = count; i-- > 0;) { value[i] = (char)(ascii[i + offset] & 0xff); } } else { hibyte <<= 8; for (int i = count; i-- > 0;) { value[i] = (char)(hibyte | (ascii[i + offset] & 0xff)); } } this.value = value; } @Deprecated public String(byte ascii[], int hibyte) { this(ascii, hibyte, 0, ascii.length); } //bytes[]:字符數組;offset:初始位置;length:長度;charsetName:編碼字符集名稱 public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException { //判斷編碼字符集,爲空拋異常 if (charsetName == null) throw new NullPointerException("charsetName"); //檢查邊界 checkBounds(bytes, offset, length); //調用StringCoding類的方法進行對應的字符集轉換。 this.value = StringCoding.decode(charsetName, bytes, offset, length); } //bytes[]:字節數組;offset:初始位置;length:長度;charset:解碼字符集 public String(byte bytes[], int offset, int length, Charset charset) { //解碼字符集爲空拋出異常 if (charset == null) throw new NullPointerException("charset"); //檢查邊界 checkBounds(bytes, offset, length); this.value = StringCoding.decode(charset, bytes, offset, length); } //重載方法 public String(byte bytes[], String charsetName) throws UnsupportedEncodingException { //直接調用上面的方法 this(bytes, 0, bytes.length, charsetName); } //重載方法,直接調用的上面的方法 public String(byte bytes[], Charset charset) { this(bytes, 0, bytes.length, charset); } //重載方法 public String(byte bytes[], int offset, int length) { checkBounds(bytes, offset, length); this.value = StringCoding.decode(bytes, offset, length); } //重載方法,直接調用以前的方法 public String(byte bytes[]) { this(bytes, 0, bytes.length); } //將一個StringBuffer對象轉換成String對象 public String(StringBuffer buffer) { //加鎖同步安全 synchronized(buffer) { //利用數組複製進行賦值。 this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } } //將一個StringBuilder對象轉換成一個String對象 public String(StringBuilder builder) { //直接利用數組複製進行賦值 this.value = Arrays.copyOf(builder.getValue(), builder.length()); } //將char數組轉換成字符串,直接賦值。 String(char[] value, boolean share) { // assert share : "unshared not supported"; this.value = value; }
/* * 此方法爲私有方法,構造函數中不少都用到這個方法,此方法是用來判斷對應數字是否超出範圍 */ private static void checkBounds(byte[] bytes, int offset, int length) { //長度不合法拋出異常 if (length < 0) throw new StringIndexOutOfBoundsException(length); //初始位置不合法,拋出異常 if (offset < 0) throw new StringIndexOutOfBoundsException(offset); //初始位置和長度組合,超出範圍拋異常 if (offset > bytes.length - length) throw new StringIndexOutOfBoundsException(offset + length); }
/** * 獲取長度,直接獲取的數組長度的屬性 */ public int length() { return value.length; }
/** * 判斷是否爲空,直接判斷長度是否爲0 * @since 1.6 */ public boolean isEmpty() { return value.length == 0; }
/** * 獲取當前下標的字符。 */ public char charAt(int index) { //判斷index是否超範圍。 if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } //返回數組中這個位置的元素。 return value[index]; }
關於Unicode字符編碼的相關方法都在這裏:測試
/** * 查詢當前位置字符的Unicode字符編碼 * @since 1.5 */ public int codePointAt(int index) { //判斷index是否超範圍。 if ((index < 0) || (index >= value.length)) { throw new StringIndexOutOfBoundsException(index); } //調用方法返回。 return Character.codePointAtImpl(value, index, value.length); } /** * 查詢前一位置字符的Unicode字符編碼 * @since 1.5 */ public int codePointBefore(int index) { int i = index - 1; if ((i < 0) || (i >= value.length)) { throw new StringIndexOutOfBoundsException(index); } return Character.codePointBeforeImpl(value, index, 0); } /** * 查詢beginIndex到endIndex之間的Unicode字符編碼,含頭不含尾。 * @since 1.5 */ public int codePointCount(int beginIndex, int endIndex) { //判斷範圍是否越界 if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) { throw new IndexOutOfBoundsException(); } return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex); } /** * * @since 1.5 */ public int offsetByCodePoints(int index, int codePointOffset) { if (index < 0 || index > value.length) { throw new IndexOutOfBoundsException(); } return Character.offsetByCodePointsImpl(value, 0, value.length, index, codePointOffset); }
/** * 將此字符串中的字符複製到目標字符數組中 * srcBegin:要複製的字符串中第一個字符的索引 */ void getChars(char dst[], int dstBegin) { //使用數組複製賦值。 System.arraycopy(value, 0, dst, dstBegin, value.length); } /** * srcBegin - 要複製的字符串中第一個字符的索引。 * srcEnd - 要複製的字符串中最後一個字符後面的索引。 * dst - 目標數組。 * dstBegin - 目標數組中的起始偏移量。 * */ public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { //判斷字符索引是否合法 if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } //判斷最後一個字符是否越界 if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } //判斷開始和結束的位置是否符合邏輯 if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } //數組拷貝 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); }
/** *已過期 */ @Deprecated public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } Objects.requireNonNull(dst); int j = dstBegin; int n = srcEnd; int i = srcBegin; char[] val = value; /* avoid getfield opcode */ while (i < n) { dst[j++] = (byte)val[i++]; } } /** * 經過指定編碼字符集獲取對象的字節數組 * @since JDK1.1 */ public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, value, 0, value.length); } /** *經過指定編碼字符集獲取對象的字節數組 * @since 1.6 */ public byte[] getBytes(Charset charset) { if (charset == null) throw new NullPointerException(); return StringCoding.encode(charset, value, 0, value.length); } /** * 使用平臺默認字符集獲取對象字節數組 * @since JDK1.1 */ public byte[] getBytes() { return StringCoding.encode(value, 0, value.length); }
/** * 判斷對象是否相等,String類將此方法重寫了。 */ public boolean equals(Object anObject) { //判斷內存地址是否相等 if (this == anObject) { //由於String是存在於方法區中的常亮,因此內存地址若是相等則相等。 return true; } //判斷對象是不是String類型 if (anObject instanceof String) { //若是是String類型,則強轉爲String類型。 String anotherString = (String)anObject; //獲取當前對象的長度 int n = value.length; //判斷長度是否相等 if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; //若是長度相等則逐一比較內容。 while (n-- != 0) { if (v1[i] != v2[i]) //有不相等的就返回false。 return false; i++; } return true;//所有相等則返回true。 } } return false;//以上兩種狀況都不符合,則返回false。 } /** * * @since 1.4 */ public boolean contentEquals(StringBuffer sb) { return contentEquals((CharSequence)sb); } private boolean nonSyncContentEquals(AbstractStringBuilder sb) { char v1[] = value; char v2[] = sb.getValue(); int n = v1.length; if (n != sb.length()) { return false; } for (int i = 0; i < n; i++) { if (v1[i] != v2[i]) { return false; } } return true; } /** * * * @since 1.5 */ public boolean contentEquals(CharSequence cs) { // Argument is a StringBuffer, StringBuilder if (cs instanceof AbstractStringBuilder) { if (cs instanceof StringBuffer) { synchronized(cs) { return nonSyncContentEquals((AbstractStringBuilder)cs); } } else { return nonSyncContentEquals((AbstractStringBuilder)cs); } } // Argument is a String if (cs instanceof String) { return equals(cs); } // Argument is a generic CharSequence 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; } } return true; } /** * 忽略大小寫比較 */ public boolean equalsIgnoreCase(String anotherString) { return (this == anotherString) ? true : (anotherString != null) && (anotherString.value.length == value.length) && regionMatches(true, 0, anotherString, 0, value.length); }
/** * 排序規則 * 返回的是數字,大於等於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; int k = 0; while (k < lim) { //挨個字符進行比較 char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; } k++; } // 有長度爲0的直接取相減的結果 return len1 - len2; } /** * 忽略大小寫排序 * @since 1.2 */ public int compareToIgnoreCase(String str) { return CASE_INSENSITIVE_ORDER.compare(this, str); } /** * 此常量是專門爲忽略大小寫建立的。 */ 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); // 自此以上的邏輯和compareTo方法的邏輯是同樣的,往下就不同了。 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) { // No overflow because of numeric promotion return c1 - c2; } } } } //若都相等,最後比的是長度的結果。 return n1 - n2; } /** */ private Object readResolve() { return CASE_INSENSITIVE_ORDER; } }
由源碼得出String的compareTo的步驟以下:ui
由源碼得出String的compareToIgnoreCase的步驟以下:this
/** * 測試兩個字符串指定子集是否相等,即指定比較的區域是否相等。 * @param toffset 當前對象子集開始的位置 * @param other 要比較的對象。 * @param ooffset 要比較的對象的子集的開始位置。 * @param len 比較的長度。 * @return 返回true表示子集相等,false表示子集不相等。 */ public boolean regionMatches(int toffset, String other, int ooffset, int len) { char ta[] = value; //當前對象的字符數組 int to = toffset; //當前對象的開始位置 char pa[] = other.value; //參數對象的字符數組 int po = ooffset; //參數對象的開始位置 // Note: toffset, ooffset, or len might be near -1>>>1. // 排除異常狀況:兩頭超範圍的排除 if ((ooffset < 0) || (toffset < 0) || (toffset > (long)value.length - len) || (ooffset > (long)other.value.length - len)) { return false; } // 比較的次數爲長度的次數 while (len-- > 0) { // 不相等就返回false if (ta[to++] != pa[po++]) { return false; } } // 所有安然度過循環,則表示相等。 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; // Note: toffset, ooffset, or len might be near -1>>>1. 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) { // 若是是true則都轉換成大寫 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; } // 平安順利的從循環中出來,則表示相等。 return true; }
/** *從toffset位置開始的以prefix開頭的字符 */ public boolean startsWith(String prefix, int toffset) { // 轉成字符數組進行比較 char ta[] = value; int to = toffset; char pa[] = prefix.value; int po = 0; int pc = prefix.value.length; // 判斷異常狀況 if ((toffset < 0) || (toffset > value.length - pc)) { return false; } // 挨個字符進行比較 while (--pc >= 0) { if (ta[to++] != pa[po++]) { return false; } } return true; } /** * 以字符prefix開頭的字符串 * @since 1. 0 */ public boolean startsWith(String prefix) { return startsWith(prefix, 0); }
/** * 判斷後綴是否與suffix相等 */ public boolean endsWith(String suffix) { // 轉換成前綴進行比較 當前對象的長度-後綴的長度=開始比較的位置 return startsWith(suffix, value.length - suffix.value.length); }
/** * */ public int hashCode() { int h = hash; // 若是存在hash值的話,直接返回,不存在,進行以下計算 if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } // 計算完成以後,存入hash成員屬性中,以便下次使用 hash = h; } return h; }
/** * 從fromIndex位置開始查找字符ch存在於當前對象的第一次出現的位置 * @param ch 字符的Unicode碼 * @param fromIndex 開始查找的位置 * @return 返回-1表示不存在,存在則返回位置。 */ public int indexOf(int ch, int fromIndex) { // 獲取當前對象的長度。 final int max = value.length; // 判斷formIndex是否非法 if (fromIndex < 0) { fromIndex = 0; //小於0,則按0開始 } else if (fromIndex >= max) { // 開始位置大於當前對象的長度,則返回-1 return -1; } // 字符小於字符補碼的最小值。 if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // 在這裏處理不少複雜的狀況,好比ch是一個BMP碼,或者是一個負數 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); } } /** * 從開始查找字符在字符串中的位置 */ public int indexOf(int ch) { //直接調用fromIndex爲0的方法。 return indexOf(ch, 0); } /** *處理帶有補充字符的indexOf的字符 */ private int indexOfSupplementary(int ch, int fromIndex) { //判斷當前字符是不是有正確的Unicode編碼 if (Character.isValidCodePoint(ch)) { final char[] value = this.value; // 獲取ch在utf-16中的編碼 final char hi = Character.highSurrogate(ch); final char lo = Character.lowSurrogate(ch); final int max = value.length - 1; //逐個字符比較編碼返回的字符,若是相等返回當前位置。 for (int i = fromIndex; i < max; i++) { if (value[i] == hi && value[i + 1] == lo) { return i; } } } //沒有相等的則返回-1 return -1; } /** * 查找字符串str在當前字符串對象中的位置。 */ public int indexOf(String str) { return indexOf(str, 0); } /** * 從fromIndex開始查找字符串str在當前字符串對象中的位置 */ public int indexOf(String str, int fromIndex) { return indexOf(value, 0, value.length, str.value, 0, str.value.length, fromIndex); } /** * 查找字符數組在字符串中的位置 * @param source 要查詢的字符數組 * @param sourceOffset 要查詢的字符數組的開始位置 * @param sourceCount 要查詢的字符數組的長度 * @param target 被查詢的字符串。 * @param fromIndex 開始查詢的位置 */ 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); } /** * 此方法爲上述幾個方法的基礎,這仍是一個靜態方法。 * @param source 要查詢的字符數組 * @param sourceOffset 要查詢的字符數組的開始位置 * @param sourceCount 要查詢的字符數組的長度 * @param target 被查詢的字符串。 * @param targetOffset 被查詢的字符串的開始位置 * @param targetCount 被查詢的字符串的長度 * @param fromIndex 開始查詢的位置 */ static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { // 判斷開始位置是否超範圍 if (fromIndex >= sourceCount) { return (targetCount == 0 ? sourceCount : -1); } //開始位置若是小於0,則按0開始 if (fromIndex < 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++) { /* Look for first character. */ if (source[i] != first) { while (++i <= max && source[i] != first); } /* Found first character, now look at the rest of v2 */ 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; } } } return -1; }
lastIndexOf()的邏輯,基本和indexOf()方法的邏輯相同。編碼
/** * 查找字符在字符串中最後出現的位置。 */ public int lastIndexOf(int ch) { return lastIndexOf(ch, value.length - 1); } /** * 從指定位置開始查找字符在字符串中出現的位置 */ public int lastIndexOf(int ch, int fromIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid 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; } } return -1; } else { return lastIndexOfSupplementary(ch, fromIndex); } } /** * 處理帶有補充字符的ch的方法 */ private int lastIndexOfSupplementary(int ch, int fromIndex) { if (Character.isValidCodePoint(ch)) { final char[] value = this.value; char hi = Character.highSurrogate(ch); char lo = Character.lowSurrogate(ch); int i = Math.min(fromIndex, value.length - 2); for (; i >= 0; i--) { if (value[i] == hi && value[i + 1] == lo) { return i; } } } return -1; } /** * 查詢字符串str在當前字符串對象中最後出現的位置 */ public int lastIndexOf(String str) { return lastIndexOf(str, value.length); } /** * 從fromIndex開始查詢字符串str在當前字符串中最後出現的位置 */ public int lastIndexOf(String str, int fromIndex) { return lastIndexOf(value, 0, value.length, str.value, 0, str.value.length, fromIndex); } /** * 從formIndex的位置開始查詢source在target中最後出現的位置 */ 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); } /** * 從fromIndex開始查詢字符數粗source從sourceOffset位置開始sourceCount個長度在target從targetOffset開始,targetCount長度中最後出現的位置 */ static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { /* * Check arguments; return immediately where possible. For * consistency, don't check for null str. */ int rightIndex = sourceCount - targetCount; if (fromIndex < 0) { return -1; } if (fromIndex > rightIndex) { fromIndex = rightIndex; } /* Empty string always matches. */ 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--; } if (i < min) { return -1; } 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; } }
/** * 從beginIndex位置開始截取到末尾 */ public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } // 獲取截取的長度 int subLen = value.length - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } // 使用構造方法新建立一個對象。 return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); } /** * 從geginIndex位置開始截取到endIndex位置,含頭不含尾。 */ public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } // 獲取截取長度 int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } // 使用構造方法新建立一個字符串對象 return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); } /** * 返回截取的字符序列 * @since 1.4 * @spec JSR-51 */ public CharSequence subSequence(int beginIndex, int endIndex) { return this.substring(beginIndex, endIndex); }
/** * 將str鏈接到當前字符串對象的末尾 */ public String concat(String str) { // 獲取參數的長度 int otherLen = str.length(); //若是參數長度爲0,返回當前對象 if (otherLen == 0) { return this; } int len = value.length; // 將當前對象複製到另一個字符數組中 char buf[] = Arrays.copyOf(value, len + otherLen); // 將str也複製到數組中 str.getChars(buf, len); // 返回數組新建的字符串對象 return new String(buf, true); }
/** * 將字符串中的oldChar替換成newChar。 */ public String replace(char oldChar, char newChar) { // 判斷兩個字符是否相等 if (oldChar != newChar) { // 獲取當前對象的長度 int len = value.length; int i = -1;//定義開始的位置 char[] val = value; //複製當前對象 //查找第一次出現oldChar的位置 while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; //複製第一次出現oldChar位置以前的字符 for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; //從第一次出現oldChar的位置開始判斷賦值 buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; } /** * 替換第一次出現的子字符串 * @since 1.4 * @spec JSR-51 */ public String replaceFirst(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceFirst(replacement); } /** * 替換全部出現的子字符串 * @since 1.4 * @spec JSR-51 */ public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } /** * 用指定的文字替換序列替換與文字目標序列匹配的字符串的每一個子字符串。替換從字符串的開始到結束,例如,將字符串「aaa」中的「aa」替換爲「b」將致使「ba」而不是「ab」。 * @since 1.5 */ public String replace(CharSequence target, CharSequence replacement) { return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); }
/** * 正則匹配 * @since 1.4 * @spec JSR-51 */ public boolean matches(String regex) { // 直接調用正則對象的方法 return Pattern.matches(regex, this); }
/** * 是否包含對象。 * @since 1.5 */ public boolean contains(CharSequence s) { // 調用indexOf()方法判斷位置的值。 return indexOf(s.toString()) > -1; }
/** * 按指定分隔符,分割指定的次數 * @param regex 分割符 * @param limit 結果閾值。若是limit大於0那麼結果的數組長度不大於limit,若是limit小於等於0,那麼結果的數組長度不受限制。 * @since 1.4 * @spec JSR-51 */ public String[] split(String regex, int limit) { char ch = 0; if (((regex.value.length == 1 &&//regex的長度=1 ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || //不包含正則的符號 // 上面兩段是一個條件:regex的長度爲1且不包含正則符號 (regex.length() == 2 &&//regex的長度=2 regex.charAt(0) == '\\' &&//regex的第一個字符爲反斜槓 (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && //regex的第二個字符不是數字 ((ch-'a')|('z'-ch)) < 0 && // 第二個字符不是小寫字母 ((ch-'A')|('Z'-ch)) < 0)) && // 第二個字符不是大寫字母 (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)) //第二個字符不是utf-16中的字符 //這是第二個容許的條件:regex是2個字符,第一個字符是反斜槓而且第二個字符不是數字、字母、utf-16的編碼 //這兩個條件的綜合表示爲單個字符和轉義字符 { int off = 0; int next = 0; boolean limited = limit > 0; ArrayList<String> list = new ArrayList<>(); // 當ch字符存在於當前字符串中,進入循環 while ((next = indexOf(ch, off)) != -1) { // 結果數組元素個數沒滿或者集合中的元素個數小於分割次數-1 if (!limited || list.size() < limit - 1) { // 從開始位置開始截取,截取到下一個分隔符以前,而後添加到集合中 list.add(substring(off, next)); // 開始截取位置挪到下一個分隔符以後 off = next + 1; } else { // 最後一個位置 //assert (list.size() == limit - 1); // 最後一次截取直接將剩餘的全部字符放入一個對象中,放入集合 list.add(substring(off, value.length)); off = value.length; //結束循環 break; } } // 若是上面沒有匹配上,將使用這個 if (off == 0) // 返回當前對象組成的數組 return new String[]{this}; // Add remaining segment if (!limited || list.size() < limit) list.add(substring(off, value.length)); // Construct result int resultSize = list.size(); // 修正集合的元素個數。 if (limit == 0) { while (resultSize > 0 && list.get(resultSize - 1).length() == 0) { resultSize--; } } // 聲明結果所用的數組 String[] result = new String[resultSize]; 將集合轉換到數組中返回。 return list.subList(0, resultSize).toArray(result); } // 若是regex是正則則使用正則的方法分割 return Pattern.compile(regex).split(this, limit); } /** * 根據regex進行分割 * @since 1.4 * @spec JSR-51 */ public String[] split(String regex) { return split(regex, 0); }
/** * 返回一個新的字符串,字符串有鏈接符鏈接每一個元素。 * @param delimiter 鏈接每一個element的字符 * @param elements 被鏈接的元素 * @since 1.8 */ public static String join(CharSequence delimiter, CharSequence... elements) { // 判斷兩個元素對象是否存在引用 Objects.requireNonNull(delimiter); Objects.requireNonNull(elements); // 以下對象是使用指定鏈接符鏈接字符序列 StringJoiner joiner = new StringJoiner(delimiter); for (CharSequence cs: elements) { joiner.add(cs); } return joiner.toString(); } /** * * @since 1.8 */ public static String join(CharSequence delimiter, Iterable< ? extends CharSequence> elements) { Objects.requireNonNull(delimiter); Objects.requireNonNull(elements); StringJoiner joiner = new StringJoiner(delimiter); for (CharSequence cs: elements) { joiner.add(cs); } return joiner.toString(); }
如下轉換爲小寫的邏輯,本人沒有看懂,因此之後待補充。.net
/** * 將字符串轉換成小寫 * @since 1.1 */ public String toLowerCase(Locale locale) { // 若是locale爲null 直接拋出異常 if (locale == null) { throw new NullPointerException(); } int firstUpper; final int len = value.length; // 開始檢查是否有字符須要修改 scan: {//循環標號 for (firstUpper = 0 ; firstUpper < len; ) { char c = value[firstUpper]; // 字符c在編碼範圍以內 if ((c >= Character.MIN_HIGH_SURROGATE) && (c <= Character.MAX_HIGH_SURROGATE)) { // 獲取當前對象第一個字符的Unicode編碼 int supplChar = codePointAt(firstUpper); 若是編碼不等於小寫的編碼,循環跳到scan位置 if (supplChar != Character.toLowerCase(supplChar)) { break scan; } firstUpper += Character.charCount(supplChar); } else { if (c != Character.toLowerCase(c)) { break scan; } firstUpper++; } } return this; } char[] result = new char[len]; int resultOffset = 0; /* result may grow, so i+resultOffset * is the write location in result */ /* Just copy the first few lowerCase characters. */ System.arraycopy(value, 0, result, 0, firstUpper); String lang = locale.getLanguage(); boolean localeDependent = (lang == "tr" || lang == "az" || lang == "lt"); char[] lowerCharArray; int lowerChar; int srcChar; int srcCount; for (int i = firstUpper; i < len; i += srcCount) { srcChar = (int)value[i]; if ((char)srcChar >= Character.MIN_HIGH_SURROGATE && (char)srcChar <= Character.MAX_HIGH_SURROGATE) { srcChar = codePointAt(i); srcCount = Character.charCount(srcChar); } else { srcCount = 1; } if (localeDependent || srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale); } else { lowerChar = Character.toLowerCase(srcChar); } if ((lowerChar == Character.ERROR) || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { if (lowerChar == Character.ERROR) { lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale); } else if (srcCount == 2) { resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount; continue; } else { lowerCharArray = Character.toChars(lowerChar); } /* Grow result if needed */ int mapLen = lowerCharArray.length; if (mapLen > srcCount) { char[] result2 = new char[result.length + mapLen - srcCount]; System.arraycopy(result, 0, result2, 0, i + resultOffset); result = result2; } for (int x = 0; x < mapLen; ++x) { result[i + resultOffset + x] = lowerCharArray[x]; } resultOffset += (mapLen - srcCount); } else { result[i + resultOffset] = (char)lowerChar; } } return new String(result, 0, len + resultOffset); } /** * */ public String toLowerCase() { return toLowerCase(Locale.getDefault()); }
轉換大寫的邏輯和轉換小寫的邏輯是同樣的。
/** * * @since 1.1 */ public String toUpperCase(Locale locale) { if (locale == null) { throw new NullPointerException(); } int firstLower; final int len = value.length; /* Now check if there are any characters that need to be changed. */ scan: { for (firstLower = 0 ; firstLower < len; ) { int c = (int)value[firstLower]; int srcCount; if ((c >= Character.MIN_HIGH_SURROGATE) && (c <= Character.MAX_HIGH_SURROGATE)) { c = codePointAt(firstLower); srcCount = Character.charCount(c); } else { srcCount = 1; } int upperCaseChar = Character.toUpperCaseEx(c); if ((upperCaseChar == Character.ERROR) || (c != upperCaseChar)) { break scan; } firstLower += srcCount; } return this; } /* result may grow, so i+resultOffset is the write location in result */ int resultOffset = 0; char[] result = new char[len]; /* may grow */ /* Just copy the first few upperCase characters. */ System.arraycopy(value, 0, result, 0, firstLower); String lang = locale.getLanguage(); boolean localeDependent = (lang == "tr" || lang == "az" || lang == "lt"); char[] upperCharArray; int upperChar; int srcChar; int srcCount; for (int i = firstLower; i < len; i += srcCount) { srcChar = (int)value[i]; if ((char)srcChar >= Character.MIN_HIGH_SURROGATE && (char)srcChar <= Character.MAX_HIGH_SURROGATE) { srcChar = codePointAt(i); srcCount = Character.charCount(srcChar); } else { srcCount = 1; } if (localeDependent) { upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale); } else { upperChar = Character.toUpperCaseEx(srcChar); } if ((upperChar == Character.ERROR) || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { if (upperChar == Character.ERROR) { if (localeDependent) { upperCharArray = ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale); } else { upperCharArray = Character.toUpperCaseCharArray(srcChar); } } else if (srcCount == 2) { resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount; continue; } else { upperCharArray = Character.toChars(upperChar); } /* Grow result if needed */ int mapLen = upperCharArray.length; if (mapLen > srcCount) { char[] result2 = new char[result.length + mapLen - srcCount]; System.arraycopy(result, 0, result2, 0, i + resultOffset); result = result2; } for (int x = 0; x < mapLen; ++x) { result[i + resultOffset + x] = upperCharArray[x]; } resultOffset += (mapLen - srcCount); } else { result[i + resultOffset] = (char)upperChar; } } return new String(result, 0, len + resultOffset); } /** * */ public String toUpperCase() { return toUpperCase(Locale.getDefault()); }
/** * 去空 */ public String trim() { int len = value.length; int st = 0; char[] val = value; /* avoid getfield opcode */ // 判斷頭部的空格位置 while ((st < len) && (val[st] <= ' ')) { st++; } // 判斷結尾的空格位置 while ((st < len) && (val[len - 1] <= ' ')) { len--; } // 若是沒有空格則返回自身,有空格返回截取掉兩頭空格的字符串 return ((st > 0) || (len < value.length)) ? substring(st, len) : this; }
/** * 字符串表示,直接返回自己 */ public String toString() { return this; }
/** * 轉換爲字符數組 */ public char[] toCharArray() { // 因爲類初始化順序的問題,這裏不能使用Arrays.copyOf。 char result[] = new char[value.length]; // 這裏使用的是另一個拷貝方法 System.arraycopy(value, 0, result, 0, value.length); return result; }
/** * 字符串格式化 * @since 1.5 */ public static String format(String format, Object... args) { return new Formatter().format(format, args).toString(); } /** * * @see java.util.Formatter * @since 1.5 */ public static String format(Locale l, String format, Object... args) { return new Formatter(l).format(format, args).toString(); }
/** * 轉化爲字符串結果 */ public static String valueOf(Object obj) { //直接調用的對象的toString()方法 return (obj == null) ? "null" : obj.toString(); } /** * char數組轉化爲字符串結果 */ public static String valueOf(char data[]) { // 直接新建一個String對象 return new String(data); } /** * 從offset位置開始,將count個data中的字符轉化成字符串。 */ 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); } /** * */ public static String copyValueOf(char data[]) { return new String(data); } /** * 返回布爾類型的字符串表示形式 */ public static String valueOf(boolean b) { return b ? "true" : "false"; } /** * 返回字符的字符串表示形式 */ public static String valueOf(char c) { char data[] = {c}; return new String(data, true); } /** * 返回int的字符串表示形式 */ public static String valueOf(int i) { return Integer.toString(i); } /** * 返回long的字符串表示形式 */ public static String valueOf(long l) { return Long.toString(l); } /** * 返回float的字符串表示形式 */ public static String valueOf(float f) { return Float.toString(f); } /** * 返回double的字符串表示形式 */ public static String valueOf(double d) { return Double.toString(d); } /** * 返回字符串對象的標準表示形式。 * 一個本地方法。 */ public native String intern();
以上就是String的所有源碼,若有錯誤請批評指正。
下一篇: