java源碼解讀之String

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&&regex.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();

}

銘記初衷,傾己所有微笑~~~


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章