天天看點

String 類源碼分析

String 類源碼分析

String 源碼分析

String 類代表字元序列,Java 中所有的字元串字面量都作為此類的執行個體。
String 對象是不可變的,它們的值在建立之後就不能改變,是以 String 是線程安全的。           
  • String 的主要屬性
/**
     *  用于存儲字元的位元組數組
     */
    @Stable
    private final byte[] value;

    /**
     *  用于對 value 位元組數組進行編碼的編碼辨別,支援 LATIN1、UTF16
     */
    private final byte coder;

    /** 緩存的哈希值 */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    /**
     *  如果字元串壓縮被禁用,則總是使用 UTF16 編碼 {@code value} 位元組數組。
     *
     *  是否啟用字元串壓縮,預設為 true
     */
    static final boolean COMPACT_STRINGS;

    static {
        COMPACT_STRINGS = true;
    }

    @Native static final byte LATIN1 = 0;
    @Native static final byte UTF16  = 1;           
  • String 執行個體化
/**
     *  建立一個空字元串
     */
    public String() {
        value = "".value;
        coder = "".coder;
    }

    /**
     *  基于目标字元數組建立字元串對象
     *
     * @param value 目标字元數組
     */
    public String(char value[]) {
        this(value, 0, value.length, null);
    }

    /**
     *  基于目标字元數組的子數組建立字元串對象
     *
     * @param  value    源目标字元數組
     * @param  offset   起始字元索引,從 0 開始   
     * @param  count    連續截取的字元個數
     */
    public String(char value[], int offset, int count) {
        this(value, offset, count, rangeCheck(value, offset, count));
    }

    /**
     *  基于指定位元組數組的子數組建立字元串執行個體
     *
     * @param  bytes    需要解碼的位元組數組
     * @param  offset   起始位元組索引
     * @param  length   截取的元素個數
     * @param  charsetName  字元集名稱
     */
    public String(byte bytes[], int offset, int length, String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null) {
            throw new NullPointerException("charsetName");
        }
        checkBoundsOffCount(offset, length, bytes.length);
        // 使用目标字元集解碼位元組數組
        final StringCoding.Result ret =
                StringCoding.decode(charsetName, bytes, offset, length);
        value = ret.value;
        coder = ret.coder;
    }

    /**
     *  基于指定位元組數組的子數組建立字元串執行個體
     *
     * @param  bytes    需要解碼的位元組數組
     * @param  offset   起始位元組索引
     * @param  length   截取的元素個數
     * @param  Charset  字元集
     */
    public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null) {
            throw new NullPointerException("charset");
        }
        checkBoundsOffCount(offset, length, bytes.length);
        final StringCoding.Result ret =
                StringCoding.decode(charset, bytes, offset, length);
        value = ret.value;
        coder = ret.coder;
    }

    /**
     *  基于目标位元組數組建立字元串執行個體。
     *
     * @param  bytes    需要解碼的位元組數組
     * @param  charsetName  字元集名稱
     */
    public String(byte bytes[], String charsetName)
            throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }

    /**
     *  基于目标位元組數組建立字元串執行個體。
     *
     * @param  bytes    需要解碼的位元組數組
     * @param  Charset  字元集
     */
    public String(byte bytes[], Charset charset) {
        this(bytes, 0, bytes.length, charset);
    }

    /**
     *  使用平台預設的字元集解碼位元組數組,建立字元執行個體
     *
     * @param  bytes    目标位元組數組
     */
    public String(byte[] bytes) {
        this(bytes, 0, bytes.length);
    }           
  • 傳回字元串的長度
/**
     *  傳回字元串的長度
     */
    @Override
    public int length() {
        return value.length >> coder();
    }           
  • 字元串是否為空
/**
     *  字元串是否為空
     */
    public boolean isEmpty() {
        return value.length == 0;
    }           
  • 擷取指定索引處的字元
/**
     *  擷取指定索引處的字元 
     *
     * @param index 目标索引
     */
    @Override
    public char charAt(int index) {
        if (isLatin1()) {
            return StringLatin1.charAt(value, index);
        } else {
            return StringUTF16.charAt(value, index);
        }
    }           
  • 讀取指定索引處的目标字元的 Unicode 代碼點
/**
     *  讀取指定索引處的目标字元的 Unicode 代碼點
     *
     * @param index 目标索引
     * @return
     */
    public int codePointAt(int index) {
        if (isLatin1()) {
            checkIndex(index, value.length);
            return value[index] & 0xff;
        }
        // UTF16 編碼的代碼點可能占用多個位元組
        final int length = value.length >> 1;
            checkIndex(index, length);
            return StringUTF16.codePointAt(value, index, length);
    }           
  • 使用指定的字元集将此字元串編碼為位元組數組并傳回
/**
     *  使用指定的字元集将此字元串編碼為位元組數組并傳回。
     *
     * @param  charsetName  目标字元集名稱
     */
    public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null) {
            throw new NullPointerException();
        }
        return StringCoding.encode(charsetName, coder(), value);
    }

    /**
     *  使用指定的字元集将此字元串編碼為位元組數組并傳回。
     *
     * @param  Charset  目标字元集
     */
    public byte[] getBytes(Charset charset) {
        if (charset == null) {
            throw new NullPointerException();
        }
        return StringCoding.encode(charset, coder(), value);
    }               
  • 使用平台預設的字元集将此字元串編碼為位元組數組并傳回
/**
     *  使用平台預設的字元集将此字元串編碼為位元組數組并傳回。
     */
    public byte[] getBytes() {
        return StringCoding.encode(coder(), value);
    }           
  • 此字元串的内容是否和目标字元串一緻
/**
     *  此字元串的内容是否和目标字元串一緻
     */
    public boolean contentEquals(CharSequence cs) {
        // 參數是一個 StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            if (cs instanceof StringBuffer) {
                synchronized(cs) {
                    return nonSyncContentEquals((AbstractStringBuilder)cs);
                }
            } else {
                return nonSyncContentEquals((AbstractStringBuilder)cs);
            }
        }
        // 參數是一個 String
        if (cs instanceof String) {
            return equals(cs);
        }
        // 參數是一個普通的字元序列 CharSequence
        final int n = cs.length();
        if (n != length()) {
            return false;
        }
        final byte[] val = value;
        if (isLatin1()) {
            for (int i = 0; i < n; i++) {
                if ((val[i] & 0xff) != cs.charAt(i)) {
                    return false;
                }
            }
        } else {
            if (!StringUTF16.contentEquals(val, cs, n)) {
                return false;
            }
        }
        return true;
    }           
  • 将此字元串和目标字元串進行比較,忽略大小寫
/**
     *  将此字元串和目标字元串進行比較,忽略大小寫
     */
    public boolean equalsIgnoreCase(String anotherString) {
        // 先比較長度,再比較内容
        return this == anotherString ? true
                : anotherString != null
                && anotherString.length() == length()
                && regionMatches(true, 0, anotherString, 0, length());
    }           
  • 此字元串指定索引開始的子字元串是否以 prefix 開頭
/**
     *  此字元串指定索引開始的子字元串是否以 prefix 開頭
     *
     * @param   prefix  字首
     * @param   toffset 起始索引
     */
    public boolean startsWith(String prefix, int toffset) {
        // Note: toffset might be near -1>>>1.
        if (toffset < 0 || toffset > length() - prefix.length()) {
            return false;
        }
        final byte ta[] = value;
        final byte pa[] = prefix.value;
        int po = 0;
        final int pc = pa.length;
        if (coder() == prefix.coder()) {
            int to = isLatin1() ? toffset : toffset << 1;
            while (po < pc) {
                if (ta[to++] != pa[po++]) {
                    return false;
                }
            }
        } else {
            if (isLatin1()) {  // && pcoder == UTF16
                return false;
            }
            // coder == UTF16 && pcoder == LATIN1)
            while (po < pc) {
                if (StringUTF16.getChar(ta, toffset++) != (pa[po++] & 0xff)) {
                    return false;
                }
            }
        }
        return true;
    }           
  • 此字元串是否以指定的字首開頭
/**
     *  此字元串是否以指定的字首開頭
     *
     * @param   prefix  目标字首
     */
    public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }           
  • 此字元串是否以指定的字尾結尾
/**
     *  此字元串是否以指定的字尾結尾
     *
     * @param suffix    目标字尾
     */
    public boolean endsWith(String suffix) {
        return startsWith(suffix, length() - suffix.length());
    }           
  • 指定字元在此字元串中第一次出現的索引
/**
     *  指定字元在此字元串中第一次出現的索引
     *
     * @param ch    目标字元
     */
    public int indexOf(int ch) {
        return indexOf(ch, 0);
    }

    /**
     *  從 fromIndex 開始,指定字元在此字元串中第一次出現的索引
     *
     * @param ch    目标字元
     * @param fromIndex 查找的起始索引
     */
    public int indexOf(int ch, int fromIndex) {
        return isLatin1() ? StringLatin1.indexOf(value, ch, fromIndex)
                : StringUTF16.indexOf(value, ch, fromIndex);
    }           
  • 目标字元在此字元串中最後一次出現的索引
/**
     *  目标字元在此字元串中最後一次出現的索引
     *
     * @param ch    目标字元
     */
    public int lastIndexOf(int ch) {
        return lastIndexOf(ch, length() - 1);
    }

    /**
     *  從 fromIndex 開始,目标字元在此字元串中最後一次出現的索引
     *
     * @param ch    目标字元
     * @param fromIndex 查找的起始索引
     */
    public int lastIndexOf(int ch, int fromIndex) {
        return isLatin1() ? StringLatin1.lastIndexOf(value, ch, fromIndex)
                : StringUTF16.lastIndexOf(value, ch, fromIndex);
    }           
  • 目标字元串 str 在此字元串中的起始索引
/**
     *  目标字元串 str 在此字元串中的起始索引
     *
     * @param str   目标字元串
     */
    public int indexOf(String str) {
        if (coder() == str.coder()) {
            return isLatin1() ? StringLatin1.indexOf(value, str.value)
                    : StringUTF16.indexOf(value, str.value);
        }
        if (coder() == LATIN1) {  // str.coder == UTF16
            return -1;
        }
        return StringUTF16.indexOfLatin1(value, str.value);
    }

    /**
     *  從起始索引 fromIndex 開始,目标字元串 str 在此字元串中的起始索引
     *
     * @param str   目标字元串
     * @param fromIndex 查找的起始索引
     */
    public int indexOf(String str, int fromIndex) {
        return indexOf(value, coder(), length(), str, fromIndex);
    }           
  • 目标字元串 str 在此字元串中最後一次出現的索引
/**
     *  目标字元串 str 在此字元串中最後一次出現的索引
     *
     * @param str   目标字元串
     */
    public int lastIndexOf(String str) {
        return lastIndexOf(str, length());
    }

    /**
     *  從起始索引 fromIndex 開始,目标字元串 str 在此字元串中最後一次出現的索引
     *
     * @param str   目标字元串
     * @param fromIndex 查找的起始索引
     */
    public int lastIndexOf(String str, int fromIndex) {
        return lastIndexOf(value, coder(), length(), str, fromIndex);
    }           
  • 截取此字元串指定索引 beginIndex 處開始到尾部的子字元串
/**
     *  截取此字元串指定索引 beginIndex 處開始到尾部的子字元串
     *
     * @param beginIndex    截取的起始索引
     */
    public String substring(int beginIndex) {
        // 1)起始索引為負數
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        final int subLen = length() - beginIndex;
        // 2)起始索引超出最大索引
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        // 3)起始索引為 0
        if (beginIndex == 0) {
            return this;
        }
        // 4)截取子字元串
        return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
                : StringUTF16.newString(value, beginIndex, subLen);
    }           
  • 截取起始索引和結束索引之間的子字元串,包括起始索引,但不包括結束索引
/**
     *  截取起始索引 beginIndex 和結束索引 endIndex 之間的子字元串,包括起始索引,但不包括結束索引
     *
     * @param      beginIndex   起始索引【包含】
     * @param      endIndex 結束索引【不包含】
     */
    public String substring(int beginIndex, int endIndex) {
        final int length = length();
        // 1)索引非法
        checkBoundsBeginEnd(beginIndex, endIndex, length);
        final int subLen = endIndex - beginIndex;
        // 2)特殊情況
        if (beginIndex == 0 && endIndex == length) {
            return this;
        }
        // 3)截取子字元串
        return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
                : StringUTF16.newString(value, beginIndex, subLen);
    }           
  • 将目标字元串 str 連接配接到此字元串的尾部
/**
     *  将目标字元串 str 連接配接到此字元串的尾部
     *
     * @param   str 目标字元串
     */
    public String concat(String str) {
        final int olen = str.length();
        // 1)目标字元串為空
        if (olen == 0) {
            return this;
        }
        // 2)編碼方式相同,則直接進行字元數組拷貝
        if (coder() == str.coder()) {
            final byte[] val = value;
            final byte[] oval = str.value;
            final int len = val.length + oval.length;
            final byte[] buf = Arrays.copyOf(val, len);
            System.arraycopy(oval, 0, buf, val.length, oval.length);
            return new String(buf, coder);
        }
        // 3)将兩個字元解碼并拷貝到目标位元組數組中
        final int len = length();
        final byte[] buf = StringUTF16.newBytesFor(len + olen);
        getBytes(buf, 0, UTF16);
        str.getBytes(buf, len, UTF16);
        return new String(buf, UTF16);
    }           
  • 将此字元串中所有的 oldChar 字元,替換為 newChar 字元
/**
     *  将此字元串中所有的 oldChar 字元,替換為 newChar 字元
     *
     * @param oldChar   舊字元
     * @param newChar   新字元
     */
    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            final String ret = isLatin1() ? StringLatin1.replace(value, oldChar, newChar)
                    : StringUTF16.replace(value, oldChar, newChar);
            if (ret != null) {
                return ret;
            }
        }
        return this;
    }           
  • 此字元串是否比對目标正規表達式 regex
/**
     *  此字元串是否比對目标正規表達式 regex
     *
     * @param regex 目标正規表達式
     */
    public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }           
  • 此字元串是否包含目标字元序列 s
/**
     *  此字元串是否包含目标字元序列 s
     *
     * @param s 待搜尋的目标字元序列
     */
    public boolean contains(CharSequence s) {
        return indexOf(s.toString()) >= 0;
    }           
  • 将第一個比對指定正規表達式 regex 的子字元串替換為 replacement
/**
     *  将第一個比對指定正規表達式 regex 的子字元串替換為  replacement
     *
     * @param regex 目标正規表達式
     * @param replacement   替換字元串
     */
    public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }           
  • 将所有比對指定正規表達式 regex 的子字元串替換為 replacement
/**
     *  将所有比對指定正規表達式 regex 的子字元串替換為  replacement
     *
     * @param regex 目标正規表達式
     * @param replacement   替換字元串
     */
    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }           
  • 将此字元串中所有的子字元串 target 替換為目标字元串 replacement
/**
     *  将此字元串中所有的子字元串 target 替換為目标字元串 replacement
     *
     * @param target    待替換字元串
     * @param replacement   替換字元串
     */
    public String replace(CharSequence target, CharSequence replacement) {
        final String tgtStr = target.toString();
        final String replStr = replacement.toString();
        int j = indexOf(tgtStr);
        if (j < 0) {
            return this;
        }
        final int tgtLen = tgtStr.length();
        final int tgtLen1 = Math.max(tgtLen, 1);
        final int thisLen = length();

        final int newLenHint = thisLen - tgtLen + replStr.length();
        if (newLenHint < 0) {
            throw new OutOfMemoryError();
        }
        final StringBuilder sb = new StringBuilder(newLenHint);
        int i = 0;
        do {
            sb.append(this, i, j).append(replStr);
            i = j + tgtLen;
        } while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
        return sb.append(this, i, thisLen).toString();
    }           
  • 使用指定的正規表達式 regex 将此字元串分割為字元串數組
/**
     *  使用指定的正規表達式 regex 将此字元串分割為字元串數組
     *
     * @param regex 目标正規表達式
     * @param limit 字元串數組的最大長度
     */
    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.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;
            final boolean limited = limit > 0;
            final 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);
                    final int last = length();
                    list.add(substring(off, last));
                    off = last;
                    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, length()));
            }

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

    /**
     *  使用指定的正規表達式 regex 将此字元串分割為字元串數組
     *
     * @param regex 目标正規表達式
     */
    public String[] split(String regex) {
        return split(regex, 0);
    }           
  • 使用指定的連接配接符 delimiter 順序連接配接可變目标字元序列數組 elements 的所有元素
/**
     *  使用指定的連接配接符 delimiter 順序連接配接可變目标字元序列數組 elements 的所有元素
     */
    public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        final StringJoiner joiner = new StringJoiner(delimiter);
        for (final CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }           
  • 使用指定的連接配接符 delimiter 順序連接配接疊代器中的所有字元序列
/**
     *  使用指定的連接配接符 delimiter 順序連接配接疊代器中的所有字元序列
     */
    public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        final StringJoiner joiner = new StringJoiner(delimiter);
        for (final CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }           
  • 使用指定的區域将此字元串的所有字元都轉換為小寫字元
/**
     *  使用指定的區域将此字元串的所有字元都轉換為小寫字元
     *
     * @param locale    目标區域
     */
    public String toLowerCase(Locale locale) {
        return isLatin1() ? StringLatin1.toLowerCase(this, value, locale)
                : StringUTF16.toLowerCase(this, value, locale);
    }

    /**
     *  使用預設的區域将此字元串的所有字元都轉換為小寫字元
     */
    public String toLowerCase() {
        return toLowerCase(Locale.getDefault());
    }           
  • 使用指定的區域将此字元串的所有字元都轉換為大寫字元
/**
     *  使用指定的區域将此字元串的所有字元都轉換為大寫字元
     *
     * @param locale    目标區域
     */
    public String toUpperCase(Locale locale) {
        return isLatin1() ? StringLatin1.toUpperCase(this, value, locale)
                : StringUTF16.toUpperCase(this, value, locale);
    }

    /**
     *  使用預設的區域将此字元串的所有字元都轉換為大寫字元
     */
    public String toUpperCase() {
        return toUpperCase(Locale.getDefault());
    }           
  • 移除此字元串前後的所有空白符
/**
     *  移除此字元串前後的所有空白符
     */
    public String trim() {
        final String ret = isLatin1() ? StringLatin1.trim(value)
                : StringUTF16.trim(value);
        return ret == null ? this : ret;
    }           
  • 基于此字元串的所有字元建立整形流
/**
     *  基于此字元串的所有字元建立整形流
     * @since 9
     */
    @Override
    public IntStream chars() {
        return StreamSupport.intStream(
                isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE)
                        : new StringUTF16.CharsSpliterator(value, Spliterator.IMMUTABLE),
                        false);
    }           
  • 基于此字元串的所有 Unicode 代碼點建立整形流
/**
     *  基于此字元串的所有 Unicode 代碼點建立整形流
     * @since 9
     */
    @Override
    public IntStream codePoints() {
        return StreamSupport.intStream(
                isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE)
                        : new StringUTF16.CodePointsSpliterator(value, Spliterator.IMMUTABLE),
                        false);
    }           
  • 将此字元串轉換為字元數組
/**
     *  将此字元串轉換為字元數組
     */
    public char[] toCharArray() {
        return isLatin1() ? StringLatin1.toChars(value)
                : StringUTF16.toChars(value);
    }           
  • 使用指定的參數清單 args 格式化目标字元串 format
/**
     *  使用指定的參數清單 args 格式化目标字元串 format
     */
    public static String format(String format, Object... args) {
        return new Formatter().format(format, args).toString();
    }           
  • 将目标對象 obj 轉換為字元串
/**
     *  将目标對象 obj 轉換為字元串
     *
     * @param obj   目标對象
     */
    public static String valueOf(Object obj) {
        return obj == null ? "null" : obj.toString();
    }           
  • 傳回此字元串的規範表示形式,将此字元串加入由 String 類管理的字元串常量池中,所有的字元串字面量和字元串常量都緩存在字元串常量池中。
public native String intern();           

posted on 2019-02-27 21:21 竺旭東 閱讀(...) 評論(...) 編輯 收藏

繼續閱讀