String类常用方法源码解析(contains,split,substring ...)

contains 方法:

字符串是否包含指定的char值序列,包含返回 true,否则返回false。

示例:

源码: 

    /**
     * Returns true if and only if this string contains the specified
     * sequence of char values.
     *
     * @param s the sequence to search for
     * @return true if this string contains {@code s}, false otherwise
     * @since 1.5
     */
    public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }

其实就是通过 indexOf 方法,获取指定字符第一次出现在字符串内的索引,如果字符串内存在指定字符 则返回 大于或等于 0 的索引值,不存在则返回 -1 。

 //  String 类的全局常量字符数组,final 修饰的变量不可以修改
    private final char value[];

   /**
     * @param   str   要搜索的子字符串
     * @return  返回指定子字符串第一次出现的索引,没有返回 -1
     */
    public int indexOf(String str) {
        return indexOf(str, 0);
    }

    /**
     * @param   str         要搜索的子字符串
     * @param   fromIndex   开始搜索的索引
     * @return  返回指定子字符串第一次出现的索引,没有返回 -1
     */
    public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }
    /**
     * @param   source       被搜索的字符数组
     * @param   sourceOffset offset of the source string.
     * @param   sourceCount  被搜索的字符数组长度
     * @param   target       要搜索的子字符数组
     * @param   targetOffset offset of the target string.
     * @param   targetCount  要搜索的子字符数组长度
     * @param   fromIndex    开始搜索的索引
     */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        // 开始搜索的索引 大于等于 字符数组长度,要搜索的子字符数组长度为0,返回字符数组长度,否则返回 -1
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        // 开始搜索的索引要大于等于 0 ,如果小于 0 就设置为 0
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        // 要搜索的子字符数组长度 等于 0 ,直接返回 开始搜索的索引
        if (targetCount == 0) {
            return fromIndex;
        }
        // 要搜索字符串的第一个字符
        char first = target[targetOffset];
        // 能获取的最大索引值
        int max = sourceOffset + (sourceCount - targetCount);

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

            /* Found first character, now look at the rest of v2 */
            // 找到第一个字符,现在看看v2的其余部分
            if (i <= max) {
                int j = i + 1; // 从第二个字符开始找
                int end = j + targetCount - 1; // 要搜索字符串结束索引
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
                // 从第二个字符开始一个一个字符的比较

                if (j == end) {
                    /* Found whole string. */
                    // 找到整个字符串
                    return i - sourceOffset; // 返回第一个字符的索引
                }
            }
        }
        return -1; // 没找到返回 -1
    }

split 方法:

将字符串分割成数组。
str.split(","); // 将str字符串,按逗号进行分割 成一个字符串数组。

示例:

也可以通过正则表达式进行匹配分割:

 源码:

    public String[] split(String regex) {
        return split(regex, 0);
    }

Java api 上这样说:

split(String regex, int limit)

limit 限制字符串最大分割个数 ,如果超过最大分割个数,limit - 1 之前的正常分割,最后子字符串的包含剩下的所有字符:

 字符串"boo:and:foo"

Regex Limit Result
: 2 { "boo", "and:foo" }
/**
*a的最小值
*<a href=“http://www.unicode.org/glossary/#high#u-surrogate_-code_-unit”>
*Unicode高代理代码单元</a>
*在UTF-16编码中,常量{@code'\u005CuD800'}。
*高代理项也称为<i>领先代理项</i>。
*
*@从1.5开始
*/
public static final char MIN_HIGH_SURROGATE = '\uD800';

/**
*a的最大值
*<a href=“http://www.unicode.org/glossary/#high#u-surrogate_-code_-unit”>
*Unicode高代理代码单元</a>
*在UTF-16编码中,常量{@code'\u005CuDBFF'}。
*高代理项也称为<i>领先代理项</i>。
*
*@从1.5开始
*/
public static final char MAX_HIGH_SURROGATE = '\uDBFF';
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.
         */
         /*如果regex是
        (1) 一个字符字符串,而此字符不是RegEx的元字符“$|()[{^”?*+\\“,
        (2) 两个字符字符串,第一个字符是反斜杠和第二个不是ascii数字或ascii字母。
         */
        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) { // 是否存在指定字符,从off位置开始匹配
                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) {
                // list最后一个元素内容长度是否为0,就是是否为空字符串
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;// 为空,就是为空就不要这个元素,直到最后元素不是空字符串
                }
            }
            String[] result = new String[resultSize];// 构建一个新数组length = resultSize
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

决定先说一下:Matcher m = matcher(input);

matcher.find()方法: 

Pattern.compile(regex).split(this, limit);源码:

    public String[] split(CharSequence input, int limit) {
        int index = 0;
        boolean matchLimited = limit > 0; // 是否限制字符串最大分割个数
        ArrayList<String> matchList = new ArrayList<>(); // 存放分割好的字符串
        Matcher m = matcher(input);

        // Add segments before each match found
        while(m.find()) {
            if (!matchLimited || matchList.size() < limit - 1) {
                if (index == 0 && index == m.start() && m.start() == m.end()) {
                    // no empty leading substring included for zero-width match
                    // at the beginning of the input char sequence.
                    continue;
                }
                String match = input.subSequence(index, m.start()).toString();
                matchList.add(match);
                index = m.end();
            } else if (matchList.size() == limit - 1) { // last one 限制字符串最大分割个数,这是最后一个
                String match = input.subSequence(index,
                                                 input.length()).toString();
                matchList.add(match);
                index = m.end();
            }
        }

        // If no match was found, return this
        // 如果找不到匹配项,返回此数组
        if (index == 0)
            return new String[] {input.toString()};

        // Add remaining segment
        // 添加剩余的字符串
        if (!matchLimited || matchList.size() < limit)
            matchList.add(input.subSequence(index, input.length()).toString());

        // Construct result
        int resultSize = matchList.size();
        if (limit == 0)
            // matchList最后一个元素内容长度是否为0
            while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
                resultSize--; // 为空,就是为空就不要这个元素,直到最后元素不是空字符串
        String[] result = new String[resultSize];
        return matchList.subList(0, resultSize).toArray(result);
    }

substring方法:

字符串截取方法:substring(int beginIndex, int endIndex);

beginIndex:开始下标。

endIndex:结束下标。

返回一个字符串,该字符串是此字符串的子字符串。

示例:

如果 str.substring (1,1); 结果会是什么呢?

左闭右开到底会不会输出下标为 1 的字符,我们来看一下源码。

源码:

    public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) { // 开始下标小于0,报下标越界异常
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) { // 结束下标大于被截取字符串总长度,报下标越界异常
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) { // 结束下标小于开始下标,报下标越界异常
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
    public String(char value[], int offset, int count) {
        if (offset < 0) { // 截取开始下标小于0,抛下标越界异常
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) { // 截取长度 <=0
            if (count < 0) { // 截取长度小于 0,抛下标越界异常
                throw new StringIndexOutOfBoundsException(count);
            }
            // 因为截取长度为 0,所以返回空字符串
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) { 
            // 截取开始下标 大于 字符串总长度 减 截取长度,抛下标越界异常
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

从源码我们可以看到,截取长度为 0 ,返回空字符串。

str.substring (1,1);的截取长度为0,所以返回空字符串。

trim 方法:

返回一个字符串,其值为此字符串,并删除任何前导和尾随空格。

示例:

源码:

    public String trim() {
        int len = value.length;
        int st = 0;
        char[] val = value;    /* avoid getfield opcode */

        while ((st < len) && (val[st] <= ' ')) { // 从 0 开始循环查找,直到不为空格或者(st >= len)
            st++;
        }
        while ((st < len) && (val[len - 1] <= ' ')) {// 从 字符串尾部 开始循环查找,直到不为空格或者(st >= len)
            len--;
        }
        // 最后调用substring方法截取,因为st 大于 len 会抛异常,所以上面判断要保证 (st <= len)
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

startsWith 方法:

测试此字符串是否以指定的前缀开头。

示例:

源码:

    public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
    }
    
    // 指定索引处开始的此字符串的子字符串是否以指定的前缀开头
    public boolean startsWith(String prefix, int toffset) {
        char ta[] = value; // 字符串的字符数组
        int to = toffset; // 开始下标
        char pa[] = prefix.value; // 指定前缀字符数组
        int po = 0;
        int pc = prefix.value.length; // 指定前缀的字符串长度
        // Note: toffset might be near -1>>>1.
        // 开始下标小于 0 或 开始下标 加 指定前缀的字符串长度 大于 字符串的总长度,直接返回 false
        if ((toffset < 0) || (toffset > value.length - pc)) {
            return false;
        }
        while (--pc >= 0) {
            if (ta[to++] != pa[po++]) { // 一个字符一个字符的比较,只要有不一样就返回 false
                return false;
            }
        }
        return true;
    }

isEmpty 方法:

判断字符串是否为空字符串,是字符串的长度为0,就是“”,记住空字符串不包括 null 为null 是会报错的。

示例:

如果字符串为 null,抛空指针异常。

源码:

    public boolean isEmpty() {
        return value.length == 0;
    }

 equals方法和hashCode方法:

请看我的另一篇文章:https://blog.csdn.net/m_crayon/article/details/105460455

终于写完了~

猜你喜欢

转载自blog.csdn.net/m_crayon/article/details/105961481