java源码解析之String类

Posted GolLong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java源码解析之String类相关的知识,希望对你有一定的参考价值。

    /*
     * 切片函数,非常重要,这里一定要牢记beginIndex是开始位置,endIndex是结束位置,区别于以前学的offset是开始位置,而count或length是个数和长度
     * 比如说,new String("abcdefg",1,3)得到的是bcd
     * 而 "abcdefg".substring(1,3)得到的是bc,也就是下标为1和2的俩个字符,并不包括c
     */
    public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        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);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen);
    }

    /*
     * 返回的是一个字符序列CharSequence,而CharSequence是一个接口,所有这里需要的是CharSequence的实现类
     * 而String实现的最后一个接口就是CharSequence,所以其实这里返回的就是String对象
     * 但是这是一个多态对象,他能调用的方法只有CharSequence接口中的几个,所以此方法没用,除非程序就需要一个CharSequence对象
     * 
     */
    public CharSequence subSequence(int beginIndex, int endIndex) {
        return this.substring(beginIndex, endIndex);
    }

    /*
     * 将指定的字符串连接到该字符串的末尾。 如果参数字符串的长度为0 ,则返回此String对象。
     * 这里使用了new String(buf, true)
     *  否则,返回一个String对象,表示一个字符序列,该字符序列是由该String对象表示的字符序列与由参数字符串表示的字符序列的级联。 
     *  如果需要大量的字符串拼接,请使用StringBuffer和StringBuilder
     */
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

    /*
     * 判断此字符串是否匹配指定的regaex正则表达式,正则表达式有些复杂,需要一章来叙述,这里不做赘述
     */
    public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }

    /*
     * 判断此字符串是否包含指定的字符序列CharSequence,CharSequence在上面已经讲过了
     */
    public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1;
    }
    /*
     * 替换字符串中的某个字符,注意参数都是字符char类型
     * 例如:"gollong".replace("o","")的结果为"gllng"
     */
    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];
                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;
    }


    /*
     * 替换字符串中的字字符串,识别方式为正则表达式
     * replaceFirst只替换第一个
     * replaceAll为全部替换
     */
    public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }
    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
    public String replace(CharSequence target, CharSequence replacement) {
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this)
                .replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }

    /*
     * 切割字符串,形参regex是一个正则表达式。limit用于限制String[]的长度
     * 例如,字符串"boo:and:foo"使用以下参数产生以下结果: 
     * Regex Limit         Result 
     * :       2       { "boo", "and:foo" } 
     * :       5       { "boo", "and", "foo" } 
     * :       -2      { "boo", "and", "foo" } 
     * o       5       { "b", "", ":and:f", "", "" } 
     * o       -2      { "b", "", ":and:f", "", "" } 
     * o       0       { "b", "", ":and:f" } 

     */
    public String[] split(String regex, int limit) {
        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);
    }
    
    public String[] split(String regex) {
        return split(regex, 0);
    }

    /*
     * 去掉字符串两端的空格,很有用的小方法
     */
    public String trim() {
        int len = value.length;
        int st = 0;
        char[] val = value; /* avoid getfield opcode */

        while ((st < len) && (val[st] <= ‘ ‘)) {
            st++;
        }
        while ((st < len) && (val[len - 1] <= ‘ ‘)) {
            len--;
        }
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
    }

    /*
     * toString返回这个对象本身,
     * 重点:我们总以为直接输出一个字符串对象可以打印其char数组的内容是因为String重写了toString方法
     *     我们认为System.out.println(str)就是System.out.println(str.toString())
     *     其实不是的,我们很清楚的看到了,toString方法就是返回一个String对象,并不是遍历
     *     于是乎我们得到了一个结论:
     *         System.out.println(str.toString())就是System.out.println(str)他们都依赖于String的特殊的实现机制
     *         这个机制就是:String s = "gollopng"就是创造对象并实例化
     *                  System.out.println(str)就是直接遍历输出
     */
    public String toString() {
        return this;
    }

    /*
     * 将字符串转换为char数组,此时联想一下charAt方法,不要记混了
     */
    public char[] toCharArray() {
        // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];
        System.arraycopy(value, 0, result, 0, value.length);
        return result;
    }
    
    /*
     * 返回字符串对象的规范表示,它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
     * 尽管在输出中调用intern方法并没有什么效果,但是实际上后台这个方法会做一系列的动作和操作。在调用”gollong”.intern()方法的时候会返回”gollong”,
     * 但是这个方法会首先检查字符串常量池中是否有”gollong”这个字符串,如果存在则该引用指向它,否则就将这个字符添加到字符串池中,然会再指向。
     */
    public native String intern();
    
    
    /*
     * 返回一个新的字符串,由 CharSequence elements的副本组成,并附有指定的delimiter的 delimiter 
     */
    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();
    }

    /*
     * 返回一个新 String的副本组成 CharSequence elements与指定的副本一起加入 delimiter 。
     */
    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(Locale locale):将字符串中所有小写字符转换为大写,其中locale用于指定自己的规则
     * toUpperCase(Locale locale):将字符串中所有大写字符转换为小写,其中locale用于指定自己的规则
     */
    public String toLowerCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }

        int firstUpper;
        final int len = value.length;

        /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstUpper = 0; firstUpper < len;) {
                char c = value[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[len];
        int resultOffset = 0; 
        System.arraycopy(value, 0, 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 < len; i += srcCount) {
            srcChar = (int) value[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
                    srcChar == ‘u0130‘) { // LATIN CAPITAL LETTER I WITH DOT ABOVE
                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
            } else {
                lowerChar = Character.toLowerCase(srcChar);
            }
            if ((lowerChar == Character.ERROR) || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (lowerChar == Character.ERROR) {
                    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(result, 0, len + resultOffset);
    }
    public String toLowerCase() {
        return toLowerCase(Locale.getDefault());
    }
    public String toUpperCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }
        int firstLower;
        final int len = value.length;
        scan: {
            for (firstLower = 0; firstLower < len;) {
                int c = (int) value[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;
        }
        int resultOffset = 0;
        char[] result = new char[len]; 
        System.arraycopy(value, 0, 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 < len; i += srcCount) {
            srcChar = (int) value[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);
                }
                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(result, 0, len + resultOffset);
    }

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

    /*
     * 使用指定的格式字符串和参数返回格式化的字符串。 Object... args是可变参数
     */
    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通过静态方法将其他类型转换为字符串
     * 总结:将其他类型转换为字符串有三种方法
     *     1.String的构造器:可以转换byte[]、char[]、int[]
     *     2.String的静态方法valueOf:可以转换Object对象、char[]、boolean、char、int、long、float、double
     *     3.其他类型的toString方法:只要是重写了toString,就可以转换
     */
    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }
    public static String valueOf(char data[]) {
        return new String(data);
    }
    public static String valueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    public static String copyValueOf(char data[]) {
        return new String(data);
    }

    public static String valueOf(boolean b) {
        return b ? "true" : "false";
    }
    public static String valueOf(char c) {
        char data[] = { c };
        return new String(data, true);
    }
    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);
    }

    

 

以上是关于java源码解析之String类的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码解析之基础应用

Java String源码解析

Java String源码解析

jdk源码解析--String 类

JDK源码解析之Java的SPI机制

Java基础1----Object类解析