阅读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,于是我们可以得出结论,没有差别。。