天天看點

JDK源碼學習筆記——String類

JDK源碼學習筆記——String類

JDK版本為1.8.0_172

String類的源碼解讀

修飾符:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
           

String類是final修飾符修飾的,不可以被繼承,是最終類。

實作的接口:

  • Serializable接口:Serializable接口是一個标記接口,用于實作序列化操作,如RMI的遠端調用,IO流寫入寫出檔案等。
  • comparable接口:該接口會對實作它的每個類進行對象的整體排序,String類實作這個接口主要是為了重寫compareTo方法。
  • charSequence接口:實作這個接口可以提供length()、charAt()、chars()方法擷取IntStream流等。

成員變量:

/** The value is used for character storage. */
	//該值用于字元存儲
	/* 構造器傳回來的字元串全部存在char[]數組中(1.9後會用bytep[]數組存儲)
	*  其加了final修飾符,擁有不可變特性
	*/
    private final char value[];

    /** Cache the hash code for the string */
    //存放字元串的哈希碼
	/*用來存放字元串經過hashcode()方法得到的hash值*/
	private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
	//使用JDK 1.0.2中的serialVersionUID進行互操作
	/*實作序列化的辨別*/
    private static final long serialVersionUID = -6849794470754667710L;
           

構造函數:

主要看這個5個函數

public String() {
        this.value = "".value;
    }

    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

    public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }
	    
	public String(byte bytes[], String charsetName)
            throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }
           

注意:

當用

String str = new String()

建立字元串時,字元串的值為 “”,而不是null。

重要函數:

equals()

方法

public boolean equals(Object anObject) {
     	//首先判斷是否是同一個引用對象
        if (this == anObject) {
            return true;
        }
     	//判斷是否是String類型
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            //判斷兩者的長度是否相同
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                //不相同則直接傳回true
                return true;
            }
        }
        return false;
    }
           

hashcode()

方法

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
            //hash值的計算過程,不同于Object類是直接使用本地方法根據存儲位址産生的
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
           

charAt()

方法

//根據索引讀取字元
public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }
           

compareTo()

方法

//compareTo就是比較兩個值,如果前者大于後者,傳回正數,等于傳回0,小于傳回負數
public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
           

compareToIgnoreCase()

方法

//該方法與compareTo()一樣,隻是忽略了大小寫
public int compareToIgnoreCase(String str) {
        return CASE_INSENSITIVE_ORDER.compare(this, str);
    }
           

concat()

方法

/*如果參數字元串的長度為 0,則傳回此 String 對象。否則,建立一個新的String對象,用來表示由此 String 對象表示的字元序列和參數字元串表示的字元序列連接配接而成的字元序列。*/
public String concat(String str) {
    	//傳進來的字元串的長度
        int otherLen = str.length();
    	//如果參數字元串的長度為 0,則傳回此 String 對象
        if (otherLen == 0) {
            return this;
        }
    	//原字元串的長度
        int len = value.length;
    	//用來存放最終形式字元串的字元數組,通過Arrays.copyOf()來實作數組複制
        char buf[] = Arrays.copyOf(value, len + otherLen);
    	//使用getChars()方法将新傳進來的字元串拼接到原來的字元串中
        str.getChars(buf, len);
    	//傳回新的字元串對象	
        return new String(buf, true);
    }
           

indexOf(String str)

indexOf(String str, int fromIndex)

方法

public int indexOf(String str) {
        return indexOf(str, 0);
    }

public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
/*source--原字元串的字元數組
 *sourceoffset--原字元串查找起始位置
 *sourceCount--原字元串的長度
 *target--目标字元串的字元數組
 *targetoffset--目标字元串查找起始位置
 *targetoCount--目标字元串的長度
 *fromIndex--查詢的起始位置
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
	   	if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }
		/*需要查找的第一個字元*/
        char first = target[targetOffset];
    	/*最大查找索引值*/
        int max = sourceOffset + (sourceCount - targetCount);

        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            /*查找第一個字元*/
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }

            /* Found first character, now look at the rest of v2 */
            /*注意 這裡的下标i隻是用來查找第一個字元,第二個字元開始用下标j*/
            /*j--第二個字元開始比對的下标
             *end--比對成功的标志位
             */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);

                if (j == end) {
                    /* Found whole string. */
                    /*找到整個字元串*/
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }
           

split(String regex)

split(String regex, int limit)

方法

public String[] split(String regex) {
        return split(regex, 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 (((regex.value.length == 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;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }
           

replace(char oldChar, char newChar)

方法

public String replace(char oldChar, char newChar) {
     	/*判斷舊字元與新字元是否相同*/
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            /*将原字元串轉為字元數組*/
            char[] val = value; /* avoid getfield opcode */
		   /*找到舊字元并跳出循環*/
            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            /*将所有的舊字元覆寫為新字元*/
            if (i < len) {
                char buf[] = new char[len];
                /*把原字元串的字元數組指派于buf[]數組*/
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

           

substring(int beginIndex)

substring(int beginIndex, int endIndex)

方法

public String substring(int beginIndex) {
        /*異常處理*/
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
       	/*subLen--截取後的長度*/
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        /*實際執行截取的代碼*/
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }


 public String substring(int beginIndex, int endIndex) {
        /*異常處理*/
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
      	/*subLen--截取後的長度*/
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
     	/*實際執行截取的代碼*/
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }