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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始


String类源码分析 -- by maxwell

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

//忽略大小写比较字符串是否相等
//使用三元运算符
public boolean equalsIgnoreCase(String anotherString) {
        return (this == anotherString) ? true //如果就是该字符串本身直接放回true
                        : (anotherString != null) //只有当下面语句都为true才返回true
                        && (anotherString.value.length == value.length)
                        && regionMatches(true, 0, anotherString, 0, value.length);  //下面将解析regionMatches()方法
}

//测试两个字符串区域是否相等。这个方法很巧妙,考虑问题很充分!值得学习!
//该方法有一个4个参数的重载版,是不考虑大小写的。public boolean regionMatches(int toffset, String other, int ooffset, int len)
/*参数说明:
        ignoreCase - 如果为 true,则比较字符时忽略大小写。
        toffset - 此字符串中子区域的起始偏移量。
        other - 字符串参数。
        toffset - 字符串参数中子区域的起始偏移量。
        len - 要比较的字符数。
*/
public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) {
        char ta[] = value; //原始字符串
        int to = toffset; //起始偏移量
        char pa[] = other.value; //要比较的字符串
        int po = ooffset; //结束偏移量
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0) //判断非法值!
                        || (toffset > (long)value.length - len) //这里考虑很充分,考虑了起始偏移量>(字符串长度-要比较的字符数)
                        || (ooffset > (long)other.value.length - len)) {
                return false;
        }
        while (len-- > 0) { //使用要比较的长度len控制循环次数
                char c1 = ta[to++]; //两个字符数组同时移位
                char c2 = pa[po++];
                if (c1 == c2) { //如果当前位相等,继续下一位
                        continue;
                }
                if (ignoreCase) { //如果是忽略了大小写比较
                        // If characters don't match but case may be ignored,
                        // try converting both characters to uppercase.
                        // If the results match, then the comparison scan should
                        // continue.
                        char u1 = Character.toUpperCase(c1); //同时转化为大写
                        char u2 = Character.toUpperCase(c2);
                        if (u1 == u2) {
                                continue;
                        }
                        // Unfortunately, conversion to uppercase does not work properly
                        // for the Georgian alphabet, which has strange rules about case
                        // conversion.  So we need to make one last check before
                        // exiting.
                        //只比较大写是不能满足世界上所有语言的,还需要比较小写是否相等
                        if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
                                continue;
                        }
                }
                return false;
        }
        return true;
}

//按字典顺序比较两个字符串。
//这是一个非常重要的方法。
//ArrayList<String>集合之所以可以使用Collections.sort()进行排序,就是因为String实现了Comparable<String>接口,实现了compareTo()方法!这是第一种方式。
public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2); //获得两个字符串长度较短的作为while()循环的次数
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0; //索引从0开始
        while (k < lim) {
                char c1 = v1[k];
                char c2 = v2[k];
                if (c1 != c2) {
                        return c1 - c2; //两个字符相减得到的是两个字符相差的ASCII值
                }
                k++;
        }
        return len1 - len2;
}

//内部类实现Comparator接口,重写compare()方法。
//因为Collection.sort()提供了两种方式实现集合可排序,这就是第二种方式。
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { //实现序列化接口
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
                int n1 = s1.length();
                int n2 = s2.length();
                int min = Math.min(n1, n2); //获得两个字符串中长度较短的作为for()循环终止条件
                for (int i = 0; i < min; i++) {
                        char c1 = s1.charAt(i);
                        char c2 = s2.charAt(i);
                        if (c1 != c2) {
                                c1 = Character.toUpperCase(c1); //先转化为大写
                                c2 = Character.toUpperCase(c2);
                                if (c1 != c2) {
                                        c1 = Character.toLowerCase(c1); //再转化为小写
                                        c2 = Character.toLowerCase(c2);
                                        if (c1 != c2) { //
                                                // No overflow because of numeric promotion
                                                return c1 - c2; //两个字符相减得到的是两个字符相差的ASCII值
                                        }
                                }
                        }
                }
                return n1 - n2;
        }
}

//测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
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.
        if ((toffset < 0) || (toffset > value.length - pc)) { //检查非法值
                return false;
        }
        while (--pc >= 0) {
                if (ta[to++] != pa[po++]) { //原字符串从to位置开始和指定前缀prefix从0开始,逐个比较
                        return false;
                }
        }
        return true;
}

//测试此字符串是否以指定的前缀开始。
//实际上是调用上面的方法实现的
public boolean startsWith(String prefix) {
        return startsWith(prefix, 0); //从0索引开始
}
//测试此字符串是否以指定的后缀结束。
//实际上也是调用上面的方法实现的
public boolean endsWith(String suffix) {
        return startsWith(suffix, value.length - suffix.value.length); //value.length - suffix.value.length即最后几位的索引开始值
}


0 个回复

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