2019/4/26

阅读String类compareTo() 方法源码以及发现的问题

compareTo()方法

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
}

从源码我们可以知道,String类使用char数组储存字符, compareTo比对时,从两个数组的第一个字符开始,验证他们的编码是不是相等,如果不相等,则返回调用String对象与作为参数传入的 String对象该位字符的差值;如果相等,进行下一个字符的比对。

以最短的字符串长度为基准,比完了长度之后,返回调用String对象长度与参数String对象长度的差值。如果等于0,说明两个字符串的存储的字符值相同;如果不相等0,数字就是调用String长度与参数String长度的相对差。

然后,源码的while语句十分吸引我,这里为什么不用for来写呢?是不是有编译上特殊的优化?

然后,我找出了字节码,并注释了对应的语句

/** compareTo字节码 */
0 aload_0
1 getfield #3 <java/lang/String.value> // int len1 = value.length
4 arraylength
5 istore_2
6 aload_1
7 getfield #3 <java/lang/String.value> // int len2 = anotherString.value.length
10 arraylength
11 istore_3
12 iload_2
13 iload_3
14 invokestatic #54 <java/lang/Math.min> // int lim = Math.min(len1, len2)
17 istore 4
19 aload_0
20 getfield #3 <java/lang/String.value> // char v1[] = value
23 astore 5
25 aload_1
26 getfield #3 <java/lang/String.value> // char v2[] = anotherString.value
29 astore 6
31 iconst_0 // int k = 0 我们可以从这里开始记录字节比对一直到77行
32 istore 7
34 iload 7
36 iload 4
38 if_icmpge 74 (+36) // k < lim
41 aload 5
43 iload 7
45 caload
46 istore 8 // char c1 = v1[k]
48 aload 6
50 iload 7
52 caload
53 istore 9 // char c2 = v2[k]
55 iload 8
57 iload 9
59 if_icmpeq 68 (+9) // if (c1 != c2)
62 iload 8
64 iload 9
66 isub // c1 - c9
67 ireturn return // c1 - c2
68 iinc 7 by 1
71 goto 34 (-37)
74 iload_2
75 iload_3
76 isub // len1 - len2
77 ireturn

接着,我写了一个测试用例,验证与for语句的差别

public class Main {
    private char[] value = new String("hello").toCharArray();

    public static void main(String[] args) {
        String s1 = "asdf";
        String s2 = "as";

        System.out.println(s1.compareTo(s2));
        Main main = new Main();
        System.out.println(main.compareToo("world"));
    }

    public int compareToo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.length();
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.toCharArray();

//        int k = 0;
//        while (k < lim) {
//            char c1 = v1[k];
//            char c2 = v2[k];
//            if (c1 != c2) {
//                return c1 - c2;
//            }
//            k++;
//        }
        for (int k = 0; k < lim; k++) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
        }
        return len1 - len2;
    }

}

测试用例的字节码

0 aload_0
1 getfield #6 <com/hdu/main/Main.value> // int len1 = value.length
4 arraylength
5 istore_2 // len1
6 aload_1
7 invokevirtual #16 <java/lang/String.length> int len2 = anotherString.length()
10 istore_3 // len2
11 iload_2
12 iload_3
13 invokestatic #17 <java/lang/Math.min>
16 istore 4 // lim
18 aload_0
19 getfield #6 <com/hdu/main/Main.value>
22 astore 5 // v1[]
24 aload_1
25 invokevirtual #5 <java/lang/String.toCharArray> // char v2[] = anotherString.toCharArray()
28 astore 6 // v2[]
30 iconst_0 // 从这里开始字节比对一直到76
31 istore 7 // k
33 iload 7
35 iload 4
37 if_icmpge 73 (+36)
40 aload 5
42 iload 7
44 caload
45 istore 8
47 aload 6
49 iload 7
51 caload
52 istore 9
54 iload 8
56 iload 9
58 if_icmpeq 67 (+9)
61 iload 8
63 iload 9
65 isub
66 ireturn
67 iinc 7 by 1
70 goto 33 (-37)
73 iload_2
74 iload_3
75 isub
76 ireturn

行号77-31=46=76-30,于是我们可以得出结论,没有差别。。

发布了25 篇原创文章 · 获赞 6 · 访问量 4794
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览