在String类中很常用的方法之一就是equals()方法,它可以判断两个字符串是否相同,知其然更要知其所以然,知道了它的作用后为了以后能更好的使用它,我们以举几个示例来来分析一下底层代码。
1.第一个示例
package equals;
public class Test {
public static void main(String[] args) {
String name1="Tom";
String name2="Tom"
System.out.println(name1.equals(name2));
}
}
按住Ctrl键点击equals方法,进入底层代码查看到以下源代码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
第1行:当name1调用该方法时,将String类型变量name2作为参数传入方法,这里可以了解到是一个对象上转型,由Object类型变量指向一个String类型对象name2。
第2行:由于是name1调用的该equals方法,所以this代指的是name1对象,所以这条语句的作用是比较name1和anObject的地址是否一致,也就是比较name1和anObject指向的name2的地址是否一致,在本例中由于name1和name2都是直接赋值的Tom字符串,所以地址是一致的,所以equals方法执行到此便进入if代码块返回true,然后方法结束。
2.第二个示例
如果赋值的是两个不同的字符串如下:
package equals;
public class Test {
public static void main(String[] args) {
String name1="Tom";
String name2="Sam"
System.out.println(name1.equals(name2));
}
}
这时我们再来分析一下底层代码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
第1行:还是一个对象上转型,由Object类型变量指向一个String类型对象name2。
第2行:比较的是name1和name2的地址是否相同,这时由于name1和name2是不同的字符串,所以地址显然不相同,此处返回false,跳出if判断条件。
第5行:因为anObject是个上转型对象,指向的是String类型的name2,所以anObject属于String类,即该判断条件返回true,执行if代码块。
第6行:新定义一个String类型变量anotherString,将anObject对象下转型为String类,用anotherString来指向anObject中的name2,这样后面就可以调用String类中的方法了。
第7行:定义一个整型n赋值为字符数组value的长度,这里的value是一个String类中的全局变量,创建String类对象name1时value便被赋值成存储name1字符串的字符数组了。
第8行:用name1创建的对象里value存放的是name1字符串,那用anotherString对象调用value自然存储的就是name2的字符串了,该语句用来判断name1和name2字符串的长度是否一致,该示例中返回值为true,所以执行if代码块。
第9、10行:定义两个字符串数组v1和v2存放两个字符串的字符数组value。
第11行:定义整型i用于遍历字符数组。
第12行:进入判断两字符串是否一致的循环中,循环次数为n,也就是字符串长度,如果在遍历中有一位字符不相同就返回false结束方法,这里的name1和name2第一个字符就不同,所以执行第一次就返回false结束方法。
3.第三个示例
当两个相同的字符串采用了两种不同的方式创建对象,就像下面这样,虽然输出结果一样,但是在底层里代码的执行情况却不一样:
package equals;
public class Test {
public static void main(String[] args) {
String name1="Tom";
String name2=new String("Tom");
System.out.println(name1.equals(name2));
}
}
还是打开刚才的底层代码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
第2行:此时虽然name1和name2的字符串相同,但是由于name1中的Tom字符串是存储在堆的常量池中,而name2中字符串是直接存储在堆中,所以地址并不相同,于是该处返回false,跳出if代码块。
第12行:此处在遍历字符数组时,二者每一个字符都一样,所以一直到循环结束。
第17行:返回true表达字符串相同。