A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始


String类源码分析 -- by maxwell

今天把String类的源码看了一遍,该类大概2000多行代码,注释就有1000多行。这个类主要都是对char[]的操作。
我大概注释了60%左右的方法,重要的方法做了分析注释,对这些方法也算有了比较深刻的认识。


//返回一个新的字符串,它是此字符串的一个子字符串。该子字符串从指定索引处的字符开始,直到此字符串末尾。
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); //直接调用String的构造方法创建子串
}

//返回一个新字符串,它是此字符串的一个子字符串。
//该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex。
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); //和上面的方法一样,也是直接调用String的构造方法创建子串
}

//将指定字符串连接到此字符串的结尾。
//实际上是调用Arrays.copyOf()处理的,而Arrays.copyOf()又是调用System.arraycopy()实现的。
public String concat(String str) {
        int otherLen = str.length(); //指定字符串str的长度
        if (otherLen == 0) { //如果指定字符串长度为0,直接返回原字符串
                return this;
        }
        int len = value.length; //原字符串长度
        char buf[] = Arrays.copyOf(value, len + otherLen); //创建一个新的字符数组,长度为两字符串长度之和,将原字符串先拷贝到里面
        str.getChars(buf, len); //再从第len位开始将str拷贝到该字符数组中
        return new String(buf, true);
}

//通过用 newChar 替换此字符串中出现的所有 oldChar 得到的一个新的字符串。
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 == oldChar) { //在原字符串中找到要替换的字符
                                break; //此时i就是该字符第一次出现的位置
                        }
                }
                if (i < len) {
                        char buf[] = new char[len]; //新建一个长度为len的字符数组
                        for (int j = 0; j < i; j++) { //从索引0开始到i-1的字符拷贝到新的字符数组中
                                buf[j] = val[j];
                        }
                        while (i < len) { //处理从i到len位置的字符,这里是个很巧妙的办法!
                                char c = val;
                                buf = (c == oldChar) ? newChar : c; //如果是oldChar,则替换为newChar,如果不是则不改变
                                i++;
                        }
                        return new String(buf, true); //构造新的字符串
                }
        }
        return this;
}

//告知此字符串是否匹配给定的正则表达式。
//这个方法直接调用了Pattern.matches()方法,跟踪到最后发现调用了Matcher类的构造方法
public boolean matches(String regex) {
        return Pattern.matches(regex, this);
}

//当前字符串是否包含了指定的 char 值序列。
//该方法只能判断是否包含,而indexOf()方法既能判断是否包含,还能返回第一次出现的位置。
//实际上,该方法就是调用了indexOf()方法来实现的!indexOf()如果不存在返回-1。
public boolean contains(CharSequence s) {
        return indexOf(s.toString()) > -1; //这里使用大于而不是等于是个好的习惯!
}

//使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
//与正则有关的方法
public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}


//根据匹配给定的正则表达式来拆分此字符串。注意返回的是String[]的数组!
//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.value.length == 1 && //如果正则表达式长度为1,并且第一个字符不是元字符
                 ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
                 (regex.length() == 2 && //如果正则表达式长度为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<>(); //这里居然用了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);
}



0 个回复

您需要登录后才可以回帖 登录 | 加入黑马