String類可以說是我們日常開發絕對會接觸到的數據類型了,而關於String類的一系列操作方法也是很常用的,因此String是我第2個看的Java源碼,還是跟Integer的源碼一樣,分析全在源碼上面,於是又可以瘋狂貼代碼了哈哈哈,下面開啓貼代碼模式..................
package java.lang;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Formatter;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* String類被final修飾,因此String類是不可被繼承的
*/
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/**
* 字符數組,用於存儲字符串的內容,用final修飾,因此可以知道String的內容一旦被
* 初始化便不可以再修改,String類中的修改其本質上都是重新指向了新的字符串,而不
* 是直接修改了原本字符串的值,String實際上就是由char[]實現的
*/
private final char value[];
/**
* 記錄char數組value中第一個有效字符的下標位置(即char數組value從是第幾個下標開始的)
*/
private final int offset;
/**
* 記錄String中字符的總個數
*/
private final int count;
/**
* 記錄字符串的hashCode值,默認爲0
*/
private int hash; // Default to 0
/**
* 由於String類實現了Serializable序列化接口,支持序列化與反序列化,因此帶有一個
* serialVersionUID,用於序列化與反序列化過程中驗證版本的一致性
* 這裏簡單介紹下Java序列化與反序列化版本一致性的校驗:
* Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性,在
* 進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的
* serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出
* 現序列化版本不一致的異常(InvalidCastException)
*/
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
/**
* String類的默認構造函數,是一個空字符串,由於String具有不可變性,因此沒必要使用
*/
public String() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}
/**
* 使用一個已存在的字符串創建一個相同字符序列的字符串
*/
public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
/**
* 當使用substring方法截取String產生新的String對象的時候,會出現這樣的情況(參考substring方法源碼):
* 當老的String對象使用其substring方法創建新的String對象的時候,新的字符數組用的還是原來老的String對象
* 的字符數組,通過substring源碼可以知道,當調用subString方法時會返回一個偏移量爲offset+beginIndex,
* 長度爲endIndex-beginIndex,value不變(即char數組不變)的String,也就是說value還是原來的value,而
* count卻已不是原來的count,因此就出現了value.length>count的情況,因此需要使用Arrays.copyOfRange
* 方法去逐一複製字符數組內容到新對象字符數組中
*/
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off+size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
/**
* 使用一個字符數組構造一個String對象,使用到了Arrays.copyOf方法將原有字符數組
* 裏面的內容逐一複製到String對象的字符數組中
*/
public String(char value[]) {
int size = value.length;
this.offset = 0;
this.count = size;
this.value = Arrays.copyOf(value, size);
}
/**
* 使用一個字符數組指定起始位置與長度構造一個String對象,使用到了Arrays.copyOf方法將
* 原有字符數組裏面的內容逐一複製到String對象的字符數組中
*/
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.offset = 0;
this.count = count;
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
/**
* 使用unicode代碼點(代碼點是指可用於編碼字符集的數字)數組,使用指定起始位置與長度構造一個字符串對象
* 瞭解下一點關於代碼點的知識:
* codePoints是代碼點,,表示的是例如’A’, ‘王’ 這種字符,每種字符都有一個唯一的數字編號,這個數字編號就叫unicode code point,
* 目前code point的數值範圍是0~0x10FFFF,codeUnit是代碼單元,它根據編碼不同而不同,可以理解爲是字符編碼的基本單元,java中的char
* 是兩個字節,也就是16位的.這樣也反映了一個char只能表示從u+0000~u+FFFF範圍的unicode字符,在這個範圍的字符也叫BMP(basic
* Multiligual Plane),超出這個範圍的叫增補字符,增補字符佔用兩個代碼單元,有高2位和低2位,可以看做是2個字符
*/
public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > codePoints.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count;
//第1步:先統計從起始位置到結束位置之間的範圍中包含的有效字符數,value字符數組的長度
//是根據代碼單元來定的,每出現一個Surrogate字符數組長度在count的基礎上加1
int n = count;
for (int i = offset; i < end; i++) {
int c = codePoints[i];
//若該代碼點是BMP代碼點(BMP代碼點的值剛好爲2^16=65535,剛好2個字節,char數組可以放得下,
//且可強轉爲char類型因此無需增加),則進入下一個循環
if (Character.isBmpCodePoint(c))
continue;
//若該代碼點是從0x0000到0x10FFFF範圍之內的有效Unicode代碼點值,超過2個字節的大小(爲增補字符),因此需要增加char數組的大小
else if (Character.isValidCodePoint(c))
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// 第2步:創建並填充字符數組,若是BMP字符則直接存儲,增補字符的用兩個char分別存儲高位和低位
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
//若該代碼點是BMP代碼點,則直接強轉爲char類型
if (Character.isBmpCodePoint(c))
v[j] = (char) c;
//若是有效Unicode代碼點(增補字符),佔用2個代碼單元,因此需要用2個char分別存儲高位與低位
else
Character.toSurrogates(c, v, j++);
}
this.value = v;
this.count = n;
this.offset = 0;
}
/**
* 使用ASCII碼字節數組構造一個String對象,過時的構造器,不深究
*/
@Deprecated
public String(byte ascii[], int hibyte, int offset, int count) {
checkBounds(ascii, offset, 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.offset = 0;
this.count = count;
this.value = value;
}
/**
* 使用ASCII碼字節數組構造一個String對象,過時的構造器,不深究
*/
@Deprecated
public String(byte ascii[], int hibyte) {
this(ascii, hibyte, 0, ascii.length);
}
/* Common private utility method used to bounds check the byte array
* and requested offset & length values used by the String(byte[],..)
* constructors.
* 用於檢查字節數組和字符串所要求的偏移量和長度值是否合法
*/
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);
}
/**
* 使用字節數組創建一個指定字符集的String對象
*/
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException
{
//若傳入的字符集爲null,則拋空指針異常
if (charsetName == null)
throw new NullPointerException("charsetName");
//檢查字節數組的偏移量與長度是否合法
checkBounds(bytes, offset, length);
//調用StringCoding的decode方法將字節數組轉換爲指定字符集的字符數組
char[] v = StringCoding.decode(charsetName, bytes, offset, length);
this.offset = 0;
this.count = v.length;
this.value = v;
}
/**
* 使用字節數組創建一個指定字符集的String對象
*/
public String(byte bytes[], int offset, int length, Charset charset) {
if (charset == null)
throw new NullPointerException("charset");
checkBounds(bytes, offset, length);
char[] v = StringCoding.decode(charset, bytes, offset, length);
this.offset = 0;
this.count = v.length;
this.value = v;
}
/**
* 使用字節數組創建一個指定字符集的String對象,默認偏移量爲0,長度爲字節數組的長度
*/
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException
{
this(bytes, 0, bytes.length, charsetName);
}
/**
*使用字節數組創建一個指定字符集的String對象,默認偏移量爲0,長度爲字節數組的長度
*/
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
/**
* 使用字節數組創建一個String對象,字符集爲虛擬機默認的字符集
*/
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
char[] v = StringCoding.decode(bytes, offset, length);
this.offset = 0;
this.count = v.length;
this.value = v;
}
/**
* 使用字節數組創建一個String對象,字符集爲虛擬機默認的字符集
*/
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
/**
* 使用一個StringBuffer對象創建String字符串,這裏實際上就是將StringBuffer以字符串形式輸出,
* 並將該字符串對象的字符數組、偏移量與字符總數賦予新的String對象
*/
public String(StringBuffer buffer) {
String result = buffer.toString();
this.value = result.value;
this.count = result.count;
this.offset = result.offset;
}
/**
* 使用一個StringBuilder對象創建String字符串,這裏實際上就是將StringBuilder以字符串形式輸出,
* 並將該字符串對象的字符數組、偏移量與字符總數賦予新的String對象
*/
public String(StringBuilder builder) {
String result = builder.toString();
this.value = result.value;
this.count = result.count;
this.offset = result.offset;
}
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
/**
* 返回該String對象的字符總數,即該String對象的長度
*/
public int length() {
return count;
}
/**
* 判斷該String是否爲空,直接判斷字符總數是否爲0即可
*/
public boolean isEmpty() {
return count == 0;
}
/**
* 返回該String對象指定位置上的字符
*/
public char charAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index + offset];
}
/**
* 返回該String對象指定位置上的Unicode代碼點
*/
public int codePointAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, offset + index, offset + count);
}
/**
* 返回該String對象指定位置之前的一個Unicode代碼點
*/
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, offset + index, offset);
}
/**
* 返回該String對象指定範圍內的Unicode代碼點數
*/
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, offset+beginIndex, endIndex-beginIndex);
}
/**
* 返回此該String中從給定的偏移量與指定數量的代碼點的位置
*/
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > count) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, offset, count,
offset+index, codePointOffset) - offset;
}
/**
* 將該String的字符數組從指定起始位置複製到傳遞進來的字符數組dst中
*/
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, offset, dst, dstBegin, count);
}
/**
* 將該String指定範圍內的字符複製到傳遞進來的指定起始位置的字符數組中
*/
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > count) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, offset + srcBegin, dst, dstBegin,
srcEnd - srcBegin);
}
/**
*將該String指定範圍內的字符轉換爲字節,並複製到傳遞進來的指定起始位置的字節數組中
*/
@Deprecated
public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > count) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
int j = dstBegin;
//計算要複製的字符數組的終止位置
int n = offset + srcEnd;
//計算要複製的字符數組的起始位置
int i = offset + srcBegin;
char[] val = value; /* avoid getfield opcode */
while (i < n) {
dst[j++] = (byte)val[i++];
}
}
/**
* 按照指定字符集名稱獲取該String的字節數組
*/
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException
{
if (charsetName == null) throw new NullPointerException();
return StringCoding.encode(charsetName, value, offset, count);
}
/**
* 按照指定字符集獲取該String的字節數組
*/
public byte[] getBytes(Charset charset) {
if (charset == null) throw new NullPointerException();
return StringCoding.encode(charset, value, offset, count);
}
/**
* 按照虛擬機默認的字符集獲取該String的字節數組
*/
public byte[] getBytes() {
return StringCoding.encode(value, offset, count);
}
/**
* 判斷該String對象內容是否與指定對象相等
* PS:==比較的是引用指向的地址,equals比較的是對象內容
* 比較的過程大致如下:
* 1.先比較兩個對象是否爲同一對象,是則返回true,否則進入步驟2;
* 2.判斷對象是否爲String類型,是則進入步驟3繼續比較,否則返回false;
* 3.再判斷兩個String對象長度是否相等,是則進入步驟4繼續比較,否則返回false;
* 4.接着比較兩個String對象上的每一個char是否相等,遇到不相等則返回false,相等則繼續比較,直到結束.
* 這一比較是一個從宏觀到微觀的過程,雖說進行了一定量的if判斷,代碼量也比較多,但在一定程度上提高了比較的效率,值得學習借鑑!
*/
public boolean equals(Object anObject) {
//若anObject引用指向的地址與該String對象指向的地址一樣,則兩者是同一個對象,返回true
if (this == anObject) {
return true;
}
//若anObject是String的實例對象,則進行比較
if (anObject instanceof String) {
//將anObject強轉爲String對象
String anotherString = (String)anObject;
int n = count;
//只有當兩個String對象的字符長度相等時纔有比較的意義,不相等則直接返回false
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
//接着逐一比較兩個String對象的value字符數組上的每一個字符,一旦遇到不相等的直接返回false
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
//anObject不是String的實例對象,直接返回false
return false;
}
/**
* 將該String與指定的StringBuffer(線程安全的)比較
*/
public boolean contentEquals(StringBuffer sb) {
//synchronized關鍵字,用於保證StringBuffer是線程安全的
synchronized(sb) {
return contentEquals((CharSequence)sb);
}
}
/**
* 將該String與指定的CharSequence比較,比較過程與equals方法相同,都是對字符數組進行逐一比較
*/
public boolean contentEquals(CharSequence cs) {
if (count != cs.length())
return false;
//當參數是StringBuffer對象時在這裏比較
if (cs instanceof AbstractStringBuilder) {
char v1[] = value;
char v2[] = ((AbstractStringBuilder)cs).getValue();
int i = offset;
int j = 0;
int n = count;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
//當參數是String類型時在這裏比較
if (cs.equals(this))
return true;
//當參數是一個普通的CharSequence對象時在這裏比較
char v1[] = value;
int i = offset;
int j = 0;
int n = count;
while (n-- != 0) {
if (v1[i++] != cs.charAt(j++))
return false;
}
return true;
}
/**
* 上面的3個比較方法equals(String)、contentEquals(StringBuffer)、contentEquals(CharSequence)
* 其核心代碼基本一樣,都是
* int n = value.length;
* while (n-- != 0) {
* if(v1[i] != v2[i])
* return false;
* i++;
* }
*/
/**
* 比較該String與其他String對象的內容,忽略大小寫,實際上就是將2個String對象的字符
* 全部轉換成大寫字母再比較,不相等則再轉換成小寫比較
*/
public boolean equalsIgnoreCase(String anotherString) {
//使用一個三目運算符和&&操作代替了多個if語句,代碼好特麼簡潔額
return (this == anotherString) ? true :
(anotherString != null) && (anotherString.count == count) &&
regionMatches(true, 0, anotherString, 0, count);
}
/**
* 依次比較兩個字符串ASC碼,如果兩個字符的ASC碼相等則繼續後續比較,
* 否則直接返回兩個ASC的差值,如果兩個字符串完全一樣,則返回0
*/
public int compareTo(String anotherString) {
int len1 = count;
int len2 = anotherString.count;
int n = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
//這裏判斷2個String對象的偏移量是否一致
if (i == j) {
/**若一致則使用一個下標去遍歷兩個String對象各自的字符數組,
* 字符相等則繼續比下去,不相等則返回兩個字符的差值
*/
int k = i;
int lim = n + i;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
} else {
/**
* 若兩個String對象的偏移量不一致,則使用各自的偏移量爲下標去遍歷各自
* 的字符數組,字符相等則繼續比下去,不相等則返回兩個字符的差值
*/
while (n-- != 0) {
char c1 = v1[i++];
char c2 = v2[j++];
if (c1 != c2) {
return c1 - c2;
}
}
}
//上面的if與else都是爲了保證兩個String對象各個字符的比較都是從偏移量開始比較的,提高比較的準確性
//若相等則返回兩個String對象的長度差
return len1 - len2;
}
/**
* String內部忽略大小寫的比較器
*/
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) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
}
/**
* 忽略大小寫的比較,直接調用String對象內部的比較器即可
*/
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
/**
* 比較兩個String對象指定區域內的字符是否相等,比較過程很簡單,也是逐一比較兩個String對象各自
* 字符數組位置上的字符是否相等
*/
public boolean regionMatches(int toffset, String other, int ooffset,
int len) {
char ta[] = value;
int to = offset + toffset;
char pa[] = other.value;
int po = other.offset + ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len)
|| (ooffset > (long)other.count - len)) {
return false;
}
while (len-- > 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
/**
* 忽略大小寫比較兩個String對象指定區域內字符是否相等
*/
public boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len) {
char ta[] = value;
int to = offset + toffset;
char pa[] = other.value;
int po = other.offset + ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len) ||
(ooffset > (long)other.count - len)) {
return false;
}
while (len-- > 0) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2) {
continue;
}
//若是忽略大小寫比較,則先將各自的字符轉換爲大寫再比較,若不相等則再轉換爲小寫比較
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
}
return false;
}
return true;
}
/**
* 判斷該String對象從指定位置開始是否以指定前綴開頭
*/
public boolean startsWith(String prefix, int toffset) {
char ta[] = value;
//計算該String對象前綴的起始位置
int to = offset + toffset;
char pa[] = prefix.value;
int po = prefix.offset;
int pc = prefix.count;
if ((toffset < 0) || (toffset > count - pc)) {
return false;
}
//循環逐一比較前綴字符是否相等,遇到不相等則返回false
while (--pc >= 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
/**
* 判斷該String對象從起始位置開始是否以指定前綴開頭
*/
public boolean startsWith(String prefix) {
return startsWith(prefix, 0);
}
/**
* 判斷該String對象是否以指定後綴結尾,實際上用的還是startsWith方法
*/
public boolean endsWith(String suffix) {
return startsWith(suffix, count - suffix.count);
}
/**
* 返回根據String對象所包含的字符而計算出hashCode值,計算公式爲
* value[0]*31^(n-1) + value[1]*31^(n-2) + ... + value[n-1]
*/
public int hashCode() {
int h = hash;
if (h == 0 && count > 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
/**
* 返回指定字符在該String對象中第一次出現的位置
*/
public int indexOf(int ch) {
return indexOf(ch, 0);
}
/**
* 從指定位置開始檢索並返回指定字符在該String對象中第一次出現的位置
*/
public int indexOf(int ch, int fromIndex) {
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= count) {
// Note: fromIndex might be near -1>>>1.
return -1;
}
/**
* 若該字符是有效代碼點(BMP代碼點),則可以正常進行檢索
* Character.MIN_SUPPLEMENTARY_CODE_POINT是分界Bmp代碼點的
* 界限,是在Java中16進制的表現形式,轉換成10進製爲62355,剛好2字節
*/
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
final char[] value = this.value;
final int offset = this.offset;
final int max = offset + count;
/**檢索過程很容易理解,就是從該String對象的(起始位置+fromIndex)爲起點
* 向後檢索,遇到指定字符則作差返回該字符的位置,沒有匹配的則返回-1
*/
for (int i = offset + fromIndex; i < max ; i++) {
if (value[i] == ch) {
return i - offset;
}
}
return -1;
} else {
//若該字符不是BMP代碼點,即爲增補字符,超過2字節,則調用indexOfSupplementary進行檢索
return indexOfSupplementary(ch, fromIndex);
}
}
/**
* 檢索過程大致是這樣的:
* 在上面關於代碼點的簡單介紹中我們知道增補字符(非BMP代碼點)佔用2個代碼單元,分爲高低2位,
* 因此我們在檢索過程中需要將指定字符拆分爲高低2位來進行檢索,只有當該String對象相鄰的2個
* 字符分別匹配指定字符的高低2位時纔算是匹配成功
*/
private int indexOfSupplementary(int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[] value = this.value;
final int offset = this.offset;
//這裏調用Character類的對應方法將指定字符拆分爲高位與低位
final char hi = Character.highSurrogate(ch);
final char lo = Character.lowSurrogate(ch);
final int max = offset + count - 1;
for (int i = offset + fromIndex; i < max; i++) {
//只有當該String對象相鄰的2個字符分別匹配指定字符的高低2位時纔算是匹配成功
if (value[i] == hi && value[i+1] == lo) {
return i - offset;
}
}
}
return -1;
}
/**
* 返回指定字符在該String對象中最後一次出現的位置
*/
public int lastIndexOf(int ch) {
return lastIndexOf(ch, count - 1);
}
/**
* 從指定位置開始檢索並返回指定字符在該String對象中最後一次出現的位置
* 檢索的情況跟indexOf類似,分爲2種:BMP代碼點與非BMP代碼點,只不
* 過indexOf是從前向後檢索,而這裏是從後向前檢索,這裏就不再贅述
*/
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;
final int offset = this.offset;
int i = offset + Math.min(fromIndex, count - 1);
for (; i >= offset ; i--) {
if (value[i] == ch) {
return i - offset;
}
}
return -1;
} else {
//非BMP代碼點調用lastIndexOfSupplementary方法另行處理
return lastIndexOfSupplementary(ch, fromIndex);
}
}
/**
* 與indexOfSupplementary類似,不多做贅述
*/
private int lastIndexOfSupplementary(int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[] value = this.value;
final int offset = this.offset;
char hi = Character.highSurrogate(ch);
char lo = Character.lowSurrogate(ch);
int i = offset + Math.min(fromIndex, count - 2);
for (; i >= offset; i--) {
if (value[i] == hi && value[i+1] == lo) {
return i - offset;
}
}
}
return -1;
}
/**
* 返回指定子字符串在該String對象中第一次出現的位置
*/
public int indexOf(String str) {
return indexOf(str, 0);
}
/**
* 從指定位置開始檢索並返回指定子字符串在該String對象中第一次出現的位置
*/
public int indexOf(String str, int fromIndex) {
return indexOf(value, offset, count,
str.value, str.offset, str.count, fromIndex);
}
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* @param source the characters being searched.
* @param sourceOffset offset of the source string.
* @param sourceCount count of the source string.
* @param target the characters being searched for.
* @param targetOffset offset of the target string.
* @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
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);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
/**
* 這個是計算該String對象最多需要遍歷的下標,即終止下標
* 比如:該String對象的count爲10,offset爲0,而指定子字符串的count爲3,
* 那麼該String對象在檢索子串的過程中最多就遍歷到下標爲(10-3)=7的位置,
* 因爲下標7加上其後的8與9共3字符恰好可能跟子串匹配,再遍歷下去剩下8與9兩字符,
* 是無論如何也不可能與子串匹配的,而且繼續匹配下去也有可能報數組下標越界異常
*/
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
//這裏是找到該String對象第一個與子字符串匹配的字符的下標位置
if (source[i] != first) {
while (++i <= max && source[i] != first);
}
/**
* 經過了上面的while循環找到了該String對象第一個與子字符串匹配的字符下標位置後,
* 先判斷下標是否到達終止下標,到達的話便沒必要執行下去;沒到達的話,則依次計算第2個
* 字符的下標與接下來該String對象需要與子串去匹配的字符數組的結束位置,即第2個字符
* 下標位置到結束位置之間的範圍就是該String對象與子串需要逐一匹配的範圍
* 比如:該String對象的count爲10,offset爲0,而指定子串的count爲5,假設我們在下標
* 爲2的位置匹配到第1個字符,則第2個字符的下標自然就是3了,結束位置就是(3+5-1)=7,
* 也就是說接下來該String對象與子串需要逐一匹配的範圍是[3,7),注意,結束位置是不參與
* 匹配的,於是接下來匹配的下標就是3、4、5、6,加上第1個已匹配的字符就是5個字符,跟子串
* 長度上可以匹配上了
*/
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) {
//當該String對象與子串整個完全匹配上了,作差返回匹配的位置
return i - sourceOffset;
}
}
}
return -1;
}
/**
*返回指定子字符串在該String對象中最後一次(最右邊)出現的下標位置
*/
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
/**
* 從指定的索引開始反向搜索(往左搜索),返回指定子字符串在該String對象中最後一次出現的下標位置
*/
public int lastIndexOf(String str, int fromIndex) {
return lastIndexOf(value, offset, count,
str.value, str.offset, str.count, fromIndex);
}
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* @param source the characters being searched.
* @param sourceOffset offset of the source string.
* @param sourceCount count of the source string.
* @param target the characters being searched for.
* @param targetOffset offset of the target string.
* @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
/**
* 計算最右邊的起始位置(該String對象與子串第1個字符匹配的字符下標位置),lastIndexOf是從右往左檢索的
* 比如:該String對象count爲10,子串count爲3,則最右邊起始下標
* 位置便爲(10-3)=7,7、8、9纔剛好有等量的字符與子串匹配,然後
* 以此爲起點向左匹配
*/
int rightIndex = sourceCount - targetCount;
if (fromIndex < 0) {
return -1;
}
if (fromIndex > rightIndex) {
fromIndex = rightIndex;
}
//空字符串是所有都匹配的,直接返回
if (targetCount == 0) {
return fromIndex;
}
//計算出子串字符數組最後一個下標位置
int strLastIndex = targetOffset + targetCount - 1;
//取出子串字符數組最後一個字符
char strLastChar = target[strLastIndex];
/**
* 這裏計算出向左檢索需要檢索到的最左邊的下標位置,小於此下標則檢索結束
* 如:"abcabdbbcfgcddd",要檢索"abc",那麼最多就檢索到2的位置,若還匹配不上則返回-1
* "abcabdbbcfgcddd" 繼續向左的話則變成這樣 "abcabdbbcfgcddd"
* "abc" "abc"
* 再向左檢索也沒意義,因爲只剩下2個字符可以匹配,是不可能匹配不上的
*/
int min = sourceOffset + targetCount - 1;
/**
* 這裏計算出該字符串對象與子串最後1個字符匹配的字符下標位置
* 如:"abcabdbbcfgcddd",要檢索"abc",fromIndex爲10,則對於前者最後一個字符的匹配是從下標爲i=12
* 位置開始的,正如indexOf是從子串第1個字符開始匹配,lastIndexOf則是從子串最後1個字符開始匹配的
* "abcabdbbcfgcddd"
* "abc"
*
*/
int i = min + fromIndex;
/**
* 以下面爲例子,對着代碼看會比較好理解:
* String s = "12345123454567567";
* s.count = 17;
* s.offset = 0
* String sub = "345";
* sub.count = 3;
* s.offset = 0;
* int from = 13;
* int strLastIndex = 2;
* char strLastChar = 5;
* int min = 2;
* int i = 15
*/
startSearchForLastChar:
while (true) {
/**於是這裏就開始循環匹配啦,只有當該String對象的字符與子串最後一個字符
* 相等是纔開始匹配子串的第2個字符(與indexOf道理一樣,就是相反了而已),
* 匹配不上就一直向左移動,直到子串最後一個字符匹配上了
*/
while (i >= min && source[i] != strLastChar) {
i--;
}
//若是到最左邊位置還是枚匹配上,則直接返回-1
if (i < min) {
return -1;
}
//記錄該String對象與子串第2個字符匹配的下標位置
int j = i - 1;
/**
* 這裏計算的是該String對象需要與子串去匹配的字符數組的結束位置,即第2個字符
* 下標位置到結束位置之間的範圍就是該String對象與子串需要逐一匹配的範圍
* 比如:該String爲"aasdxrewsdccs",子串爲"abcdw",於是會在下標爲7的地方匹配
* 到子串最後1個字符'w',那麼此時該String對象要與子串匹配的字符數組的結束位置就是
* 6-(5-1)=2,也就是說接下來該String對象與子串需要逐一匹配的範圍是(2,6],注意,
* 結束位置是不參與匹配的,於是接下來匹配的下標就是3、4、5、6,加上第1個已匹配的字符
* 就是5個字符,跟子串長度上可以匹配上了
*/
int start = j - (targetCount - 1);
int k = strLastIndex - 1;
while (j > start) {
//這裏顯而易見就是在一一匹配,不相等則繼續上一層循環
if (source[j--] != target[k--]) {
i--;
continue startSearchForLastChar;
}
}
//匹配得上的話就直接計算返回下標啦
return start - sourceOffset + 1;
}
}
/**
* 分析完indexOf與lastIndexOf做下小總結:
* 兩者的對子串字符整串的一一匹配都有一個前提,就是在與子串"第1個字符"相等的前提下,才觸發
* 整串的比較,而不是一上來就劃定個範圍整串一一匹配,因爲第1個字符都不相等的話,那接下
* 來的匹配也都是毫無意義的,這在一定程度上提高了檢索的效率
* 上面說的"第1個字符"是相對而言的,對於indexOf是從左到右檢索的,那麼子串的"第1個字符"自然
* 就是最左邊的那個,對於lastIndexOf是從右到左檢索的,則子串的"第1個字符"自然就是最右邊那個咯
*/
/**
* 從指定位置開始,到該String對象結尾,返回一個新的字符串,它是該String對象的一個子字符串
*/
public String substring(int beginIndex) {
return substring(beginIndex, count);
}
/**
* 返回該String對象從指定起始位置到結束位置的子字符串
*/
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
/**
* 若開始位置爲0且結束位置等於該String對象的字符數組總數,則直接將該String對象返回,
* 否則利用該String對象的字符數組與制定的開始位置與結束位置新建一個String對象返回,
* 這也是爲什麼我們常說String是不可變的,其方法返回的字符串都是新的字符串
*/
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
/**
* 返回一個新的字符序列,它是此序列的一個子序列
*/
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
}
/**
* 將指定字符串連接到該String對象的結尾,也是返回一個新的String對象
*/
public String concat(String str) {
int otherLen = str.length();
//若指定字符串爲空串,則直接返回該String對象本身
if (otherLen == 0) {
return this;
}
//新建一個長度爲該String對象與指定字符串總長度的字符數組
char buf[] = new char[count + otherLen];
//將該String對象的字符複製到新的字符數組中
getChars(0, count, buf, 0);
//將指定字符串的字符在上面之後複製到新的字符數組中
str.getChars(0, otherLen, buf, count);
//利用新建的字符數組創建新的String對象並返回
return new String(0, count + otherLen, buf);
}
/**
* 返回一個新的字符串,它是通過用 newChar替換該String對象中出現的所有 oldChar得到的
*/
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = count;
int i = -1;
char[] val = value; /* avoid getfield opcode */
int off = offset; /* avoid getfield opcode */
/**
* 從該String對象起始位置開始,循環比較字符與指定要替換的字符是否相等,
* 若相等則退出循環,此時i的位置就是第1個餘指定字符匹配的位置;若到該
* String對象結尾還未匹配上,則直接返回該String對象
*/
while (++i < len) {
if (val[off + i] == oldChar) {
break;
}
}
//若找到該String對象第一個與指定字符匹配的字符之後還未遍歷完
if (i < len) {
//則新建一個字符數組,長度與該String對象一致
char buf[] = new char[len];
//填充新建的字符數組
for (int j = 0 ; j < i ; j++) {
buf[j] = val[off+j];
}
//繼續循環並將匹配的字符替換成指定新字符
while (i < len) {
char c = val[off + i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
//返回替換後的新的字符串對象
return new String(0, len, buf);
}
}
//若指定替換的新老字符相等,則直接返回該String對象
return this;
}
/**
* 判斷該String對象是否匹配給定的正則表達式
*/
public boolean matches(String regex) {
return Pattern.matches(regex, this);
}
/**
* 判斷該String對象是否包含指定的字符序列
* 直接調用indexOf方法檢索該String對象中次字符序列的位置,
* 存在則返回大於-1的數,不存在則返回-1
*/
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
/**
* 使用指定的字符串替換該String對象匹配給定的正則表達式的第1個子字符串
*/
public String replaceFirst(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
/**
* 使用指定的字符串替換該String對象匹配給定的正則表達式的所有子字符串
*/
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
/**
* 使用指定的字符序列替換該String對象中所有匹配目標字符序列的子字符串
*/
public String replace(CharSequence target, CharSequence replacement) {
return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}
/**
* 根據給定正則表達式的匹配分割該String對象成limit份,limit<=0時能分割成多少份就多少份
*/
public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
/**
* 看到這麼一個if判斷是不是很恐怖,莫方,咱來把簡化一下,這其實就是這麼個if判斷
* if(((A)||(B))&&(C)) 而具體各個判斷是在判斷什麼,咱慢慢解釋
* A=A1 && A2 是判斷該正則表達式是否長度爲1且不包含".$|()[{^?*+\\"其中的任何一個字符
* B=B1 && B2 && B3 && B4 && B5
* 其中B1判斷該正則表達式是否長度爲2
* B2判斷該正則表達式是否以'\\'開頭
* B3判斷該正則表達式第2個字符ch是否爲ch<'0' | ch>'9' 即ch<'0' && ch>'9'
* B4判斷該正則表達式第2個字符ch是否爲ch<'a' | ch>'z' 即ch<'a' && ch>'z'
* B5判斷該正則表達式第2個字符ch是否爲ch<'A' | ch>'Z' 即ch<'A' && ch>'Z'
* C判斷該正則表達式第2個字符ch是否小於UTF-16編碼中的 Unicode高代理項代碼單元的最小值
* 或大於UTF-16編碼中的Unicode低代理項代碼單元的最大值
* 總之,這個if判斷的是該正則表達式長度只有1或2的情況下的,其下面的處理也是針對長度爲1或2的正則表達式
*/
if (((regex.count == 1 &&".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2&®ex.charAt(0) =='\\'&&(((ch = regex.charAt(1))-'0')|('9'-ch))<0&&((ch-'a')|('z'-ch)) < 0 &&((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
//當傳遞進來的limit>0時,則該String對象按正則表達式分割成limit份,limit<=0時,該String對象能分割成多少就多少
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
//這裏開始循環indexOf匹配,若匹配得到
while ((next = indexOf(ch, off)) != -1) {
//則判斷要分割的字符串份數是否達到指定limit-1份,未達到則截取子串放到list集合中(!limited結合上面對limited的註釋悟)
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//若達到指定的limit-1份,則將剩餘的字符串作爲最後一份放入list集合中,循環結束
list.add(substring(off, count));
off = count;
break;
}
}
//若匹配不到則返回該String對象本身的拷貝
if (off == 0)
return new String[] { this };
//若循環結束仍未達到指定limit份數或!limited(悟)
if (!limited || list.size() < limit)
//則將剩餘的字符串作爲最後一份放入list集合中
list.add(substring(off, count));
//這裏開始統計實際上分割的子字符串總份數
int resultSize = list.size();
//若limit==0 即能分割多少份就多少份
if (limit == 0)
//則循環判斷子串是否是空串,是的話則實際總份數減1
while (resultSize > 0 && list.get(resultSize-1).length() == 0)
resultSize--;
String[] result = new String[resultSize];
//將list集合轉換成字符串數組並返回
return list.subList(0, resultSize).toArray(result);
}
//若該正則表達式長度大於2則使用正則表達式特有的方法去處理
return Pattern.compile(regex).split(this, limit);
}
/**
* 根據給定正則表達式的匹配分割該String對象
*/
public String[] split(String regex) {
return split(regex, 0);
}
/**
* 使用給定的Locale語言環境的規則將該String對象中的所有字符都轉換爲小寫,涉及的東西過於複雜,學識短淺,我投翔
*/
public String toLowerCase(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int firstUpper;
/* Now check if there are any characters that need to be changed. */
scan: {
for (firstUpper = 0 ; firstUpper < count; ) {
char c = value[offset+firstUpper];
if ((c >= Character.MIN_HIGH_SURROGATE) &&
(c <= Character.MAX_HIGH_SURROGATE)) {
int supplChar = codePointAt(firstUpper);
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[count];
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, offset, 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 < count; i += srcCount) {
srcChar = (int)value[offset+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
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
} else if (srcChar == '\u0130') { // LATIN CAPITAL LETTER I DOT
lowerChar = Character.ERROR;
} else {
lowerChar = Character.toLowerCase(srcChar);
}
if ((lowerChar == Character.ERROR) ||
(lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
if (lowerChar == Character.ERROR) {
if (!localeDependent && srcChar == '\u0130') {
lowerCharArray =
ConditionalSpecialCasing.toLowerCaseCharArray(this, i, Locale.ENGLISH);
} else {
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(0, count+resultOffset, result);
}
/**
* 使用默認語言環境的規則將該String對象中的所有字符都轉換爲小寫
*/
public String toLowerCase() {
return toLowerCase(Locale.getDefault());
}
/**
* 使用指定的語言環境的規則將該String對象中的所有字符都轉換爲大寫,涉及的東西過於複雜,學識短淺,我投翔
*/
public String toUpperCase(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int firstLower;
/* Now check if there are any characters that need to be changed. */
scan: {
for (firstLower = 0 ; firstLower < count; ) {
int c = (int)value[offset+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;
}
char[] result = new char[count]; /* may grow */
int resultOffset = 0; /* result may grow, so i+resultOffset
* is the write location in result */
/* Just copy the first few upperCase characters. */
System.arraycopy(value, offset, 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 < count; i += srcCount) {
srcChar = (int)value[offset+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(0, count+resultOffset, result);
}
/**
* 使用默認語言環境的規則將該String對象中的所有字符都轉換爲大寫
*/
public String toUpperCase() {
return toUpperCase(Locale.getDefault());
}
/**
* 去除該String對象前後的空格,若該String對象前後無空格則返回其本身,若有則返回其拷貝
*/
public String trim() {
int len = count;
int st = 0;
int off = offset; /* avoid getfield opcode */
char[] val = value; /* avoid getfield opcode */
//從左到右檢索空格
while ((st < len) && (val[off + st] <= ' ')) {
st++;
}
//從右到左檢索空格
while ((st < len) && (val[off + len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < count)) ? substring(st, len) : this;
}
public String toString() {
return this;
}
/**
* 以字符數組形式返回該String對象的字符,返回的是改String對象字符數組的一份拷貝
*/
public char[] toCharArray() {
char result[] = new char[count];
getChars(0, count, result, 0);
return result;
}
/**
* 使用指定的格式字符串和參數返回一個格式化字符串
*/
public static String format(String format, Object ... args) {
return new Formatter().format(format, args).toString();
}
/**
* 使用指定的語言環境、格式字符串和參數返回一個格式化字符串
*/
public static String format(Locale l, String format, Object ... args) {
return new Formatter(l).format(format, args).toString();
}
/**
* 將對象轉換爲String對象
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
/**
* 將字符數組轉換爲String對象
*/
public static String valueOf(char data[]) {
return new String(data);
}
/**
* 將指定字符數組,從指定起始位置開始的count個字符轉換爲字符串對象
*/
public static String valueOf(char data[], int offset, int count) {
return new String(data, offset, count);
}
/**
* 這個方法其實跟valueOf(char data[], int offset, int count)沒啥區別,那爲毛它出現在這?難不成是String的私生子?
* 其實,是因爲早期的String構造器的實現呢,不會拷貝數組的,直接將參數的char[]數組作爲String的value屬性,這就導致字符串發生
* 變化,這就跟說好的String對象是不可變的衝突了呀,於是爲了避免這個問題,提供了copyValueOf方法,每次都拷貝成新的字符數組來構
* 造新的String對象,但是現在的String對象,在構造器中就通過拷貝新數組實現了,所以這兩個方面在本質上已經沒區別啦
*/
public static String copyValueOf(char data[], int offset, int count) {
return new String(data, offset, count);
}
/**
* 同上
*/
public static String copyValueOf(char data[]) {
return copyValueOf(data, 0, data.length);
}
public static String valueOf(boolean b) {
return b ? "true" : "false";
}
public static String valueOf(char c) {
char data[] = {c};
return new String(0, 1, data);
}
public static String valueOf(int i) {
return Integer.toString(i);
}
public static String valueOf(long l) {
return Long.toString(l);
}
public static String valueOf(float f) {
return Float.toString(f);
}
public static String valueOf(double d) {
return Double.toString(d);
}
/**
* 本地方法,將該String對象放入常量池,下次使用到相同的字符串時將會直接去常量池獲取
*/
public native String intern();
}