String源码详解三

String源码详解三

indexOf

返回字符串对应数字编码字符的下标位置
indexOf(int ch)

    public static void main(String[] args) {
    	//97对应的字符是a,返回hallo中第一个a的下标
        int b = "hallo".indexOf(97);
        System.out.println(b); //结果为1
    }

indexOf(int ch, int fromIndex)

    public static void main(String[] args) {
    	//97对应的字符为a,返回“halao”从下标2开始找字符为a的下标数
        int b = "halao".indexOf(97,2);
        System.out.println(b); //结果为3
    }

indexOf(String str)

    public static void main(String[] args) {
    	//a字符串在halao中第一个开始出现的下标
        int a = "halao".indexOf("a"); //  1
        //al字符串在halao中第一次出现的下标
        int b = "halao".indexOf("al"); //  1
        //ab字符串在halao第一处出现的下标,没有则返回-1
        int c = "halao".indexOf("ab"); //  -1
    }

indexOf(String str, int fromIndex)
重载方法和上面的一样,有个参数即从这个参数位置开始找

indexOf(byte[] src, byte srcCoder, int srcCount, String tgtStr, int fromIndex)
列出其中一个核心方法的源码。
src 代表源字符串的字节数组
srcCoder 代表源字符串的编码方式
srcCount 代表源字符串的长度
tgtStr 代表子串
fromIndex 代表源字符串开始查找的下标位置

    static int indexOf(byte[] src, byte srcCoder, int srcCount,
                       String tgtStr, int fromIndex) {
        byte[] tgt    = tgtStr.value;
        byte tgtCoder = tgtStr.coder();
        int tgtCount  = tgtStr.length();
		//如果开始查找的位置大于源字符串的长度,如果子串是空字符串就返回源字符串的长度
		//否则返回-1
        if (fromIndex >= srcCount) {
            return (tgtCount == 0 ? srcCount : -1);
        }
        //下标开始处如果小于0则等于0
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        //如果子串是空串,则下标处是几则返回几
        if (tgtCount == 0) {
            return fromIndex;
        }
        //如果子串的长度大于源字符串则返回-1
        if (tgtCount > srcCount) {
            return -1;
        }
        //根据不同的编码格式调用不同的方法来进行判断
        if (srcCoder == tgtCoder) {
            return srcCoder == LATIN1
                ? StringLatin1.indexOf(src, srcCount, tgt, tgtCount, fromIndex)
                : StringUTF16.indexOf(src, srcCount, tgt, tgtCount, fromIndex);
        }
        // 到这里说明编码方式不一样,源字符串为LATIN1,说明子串为UTF16,那么源字符串里面
        //肯定不会有子串,相当于英文字母数字组成的字符串中能出现汉字?
        if (srcCoder == LATIN1) {    //  && tgtCoder == UTF16
            return -1;
        }
        //源字符串为UTF16则再进行计算,相当于源字符串里面可能包含数字字母等。
        //比如“你好nihao”是UTF16编码 "nihao"是Latin1编码,这样子就能进行比较
        // srcCoder == UTF16 && tgtCoder == LATIN1) {
        return StringUTF16.indexOfLatin1(src, srcCount, tgt, tgtCount, fromIndex);
    }

lastIndexOf

和IndexOf方法类似,只不过返回的是源字符串匹配子串的最后一个匹配的下标

    public static void main(String[] args) {
        int a = "halao".lastIndexOf("a"); //  1
        System.out.println(a);//  3
    }

和IndexOf()方法一样,也是有好几个重载方法,参数的含义也是一样的,就不多说了
lastIndexOf(int ch)
lastIndexOf(int ch, int fromIndex)
lastIndexOf(String str)
lastIndexOf(String str, int fromIndex)

    static int lastIndexOf(byte[] src, byte srcCoder, int srcCount,
                           String tgtStr, int fromIndex) {
        byte[] tgt = tgtStr.value;
        byte tgtCoder = tgtStr.coder();
        int tgtCount = tgtStr.length();
        /*
         * Check arguments; return immediately where possible. For
         * consistency, don't check for null str.
         */
        int rightIndex = srcCount - tgtCount;
        if (fromIndex > rightIndex) {
            fromIndex = rightIndex;
        }
        if (fromIndex < 0) {
            return -1;
        }
        /* Empty string always matches. */
        if (tgtCount == 0) {
            return fromIndex;
        }
        if (srcCoder == tgtCoder) {
            return srcCoder == LATIN1
                ? StringLatin1.lastIndexOf(src, srcCount, tgt, tgtCount, fromIndex)
                : StringUTF16.lastIndexOf(src, srcCount, tgt, tgtCount, fromIndex);
        }
        if (srcCoder == LATIN1) {    // && tgtCoder == UTF16
            return -1;
        }
        // srcCoder == UTF16 && tgtCoder == LATIN1
        return StringUTF16.lastIndexOfLatin1(src, srcCount, tgt, tgtCount, fromIndex);
    }

substring

这个方式是截取字符串的一个子串,有两个重载方法
substring(int beginIndex) //从指定下标处截取

System.out.println("abcd".substring(1));//bcd

从指定下标截取,截取到指定结尾下标位置
substring(int beginIndex, int endIndex)

        System.out.println("abcd".substring(1,3));//bc

以其中一个源码说明

    public String substring(int beginIndex) {
    	//开始下标小于0,直接抛异常
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        //开始下标大于字符串长度,也是直接抛异常
        int subLen = length() - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        //开始下标等于0,返回这个字符串
        if (beginIndex == 0) {
            return this;
        }
        //根据不同的编码再生成一个新的字符串,
        //所以截取这个方法是没有直接在原来的字符串上进行截取,因为String是不可变的。
        return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
                          : StringUTF16.newString(value, beginIndex, subLen);
    }

subSequence

看源码可知,这个方法就是调用subString,即作用也是截取指定的子串

    public CharSequence subSequence(int beginIndex, int endIndex) {
        return this.substring(beginIndex, endIndex);
    }

concat

两个字符串进行拼接

    public String concat(String str) {
        int olen = str.length();
        //拼接的是空字符串,直接返回源串
        if (olen == 0) {
            return this;
        }
        //两个字符串编码格式相同,那么将两个字符串合并成一个新字符串
        if (coder() == str.coder()) {
            byte[] val = this.value;
            byte[] oval = str.value;
            int len = val.length + oval.length;
            byte[] buf = Arrays.copyOf(val, len);
            System.arraycopy(oval, 0, buf, val.length, oval.length);
            return new String(buf, coder);
        }
        //如果两个字符串编码格式不一样,那么就按UTF16进行编码,合并成一个新字符串。
        int len = length();
        byte[] buf = StringUTF16.newBytesFor(len + olen);
        getBytes(buf, 0, UTF16);
        str.getBytes(buf, len, UTF16);
        return new String(buf, UTF16);
    }

replace replaceFirst replaceAll

这三个方法都是替换字符串,产生一个新的字符串
replace第一个参数是被替代的字符,第二个参数是要替换成哪个字符。只要符合的全部替换

    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            String ret = isLatin1() ? StringLatin1.replace(value, oldChar, newChar)
                                    : StringUTF16.replace(value, oldChar, newChar);
            if (ret != null) {
                return ret;
            }
        }
        return this;
    }

	    public String replace(CharSequence target, CharSequence replacement) {
        String tgtStr = target.toString();
        String replStr = replacement.toString();
        int j = indexOf(tgtStr);
        if (j < 0) {
            return this;
        }
        int tgtLen = tgtStr.length();
        int tgtLen1 = Math.max(tgtLen, 1);
        int thisLen = length();

        int newLenHint = thisLen - tgtLen + replStr.length();
        if (newLenHint < 0) {
            throw new OutOfMemoryError();
        }
        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();
    }

replaceFirst 第一个参数可以是被替换的字符,也可以是正则表达式,从方法名可以看出来只替换第一个符合的。

    public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }

replaceAll
和replace不同的就是第一个参数可以为正则表达式。其余的一样,当两个方法的第一个参数都为要替换的字符串时,没有任何区别。

    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

split

根据匹配给定的正则表达式来拆分字符串
regex 是正则表达式,或者字符串
limit 是要拆分的份数
有两个重载方法
split(String regex) 默认limit是0 ,代表能分几份就是几份
split(String regex, int 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;
            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);
                    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--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }

join

join()方法是用指定字符来拼接多个字符串的,例如
  String result = String.join("-",“A”,“B”,“C”,“D”);
  结果:A-B-C-D
  或者另一种用法:
  String[] arr = {"-",“A”,“B”,“C”,“D”};
  String result = String.join("-",arr);
  结果:A-B-C-D

参数列表:
  1、表示连接的符号
  2、表示被连接的数组(也可以是集合),或者是要连接的多个字符串
  有两个重载的方法如下是源码:

    public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

	    public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

toLowerCase

把字符串里面的英文单词都转换为小写,对中文没影响

        String s = "asdadssA你好".toLowerCase();
        //asdadssa你好

从源码可以看出里面还可以传个参数是Local,代表不同的区域。区域不一样进行转换可能会出现问题。

    public String toLowerCase() {
        return toLowerCase(Locale.getDefault());
    }

toUpperCase

把字符串里面的英文单词都转换为大写,对中文没影响

        String s = "asdadssA你好".toLowerCase();
        //ASDADSSA你好
    public String toUpperCase() {
        return toUpperCase(Locale.getDefault());
    }

trim

去除字符串两边的空白字符,中间的空白字符无法去除

String trim = "   a a a a    ".trim();
//a a a a
    public String trim() {
        String ret = isLatin1() ? StringLatin1.trim(value)
                                : StringUTF16.trim(value);
        return ret == null ? this : ret;
    }

chars

这个方法返回字符串的int字符的流

    public IntStream chars() {
        return StreamSupport.intStream(
            isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE)
                       : new StringUTF16.CharsSpliterator(value, Spliterator.IMMUTABLE),
            false);
    }

codePoints

这个方法同样返回字符串int字符的流,不同的在于代码点可能由于unicode中没有而返回的值不一致。

    public IntStream codePoints() {
        return StreamSupport.intStream(
            isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE)
                       : new StringUTF16.CodePointsSpliterator(value, Spliterator.IMMUTABLE),
            false);
    }

toCharArray

这个方法很简单就是返回字符串的字符数组

    public char[] toCharArray() {
        return isLatin1() ? StringLatin1.toChars(value)
                          : StringUTF16.toChars(value);
    }

format

这个方法实用性很强,是用来对字符串进行动态替换和格式化的,玩法多种多样,我一般用过的就是对日期进行处理,这里详细用法不做过多解释,可以参数format详细用法

    public static String format(String format, Object... args) {
        return new Formatter().format(format, args).toString();
    }

valueOf

这个方法也很常用,用来将参数类型的数据转换为String类型
这里有狠多重载方法,可以将多种类型都转换为字符串。
在这里插入图片描述

copyValueOf

这个方法是重新拷贝一个新的字符串
传入的是字符数组,从源代码可以看出是以字符数组来重新生成一个字符串
参数offset是生成字符串的开始下标,count是生成的长度

        char[] chars = "你好".toCharArray();
        String s = "wo".copyValueOf(chars,0,1);
        System.out.println(s); //结果为“你”
    public static String copyValueOf(char data[]) {
        return new String(data);
    }
		
	    public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

intern

这个方法是一个本地方法,用来往常量池里面放引用的,这个底层关联的知识点很多,由于篇幅原因,就不展开说了,可以看看其他资料。

 public native String intern();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值