一. 面试题及剖析
1. 今日面试题
每日一题,请跟着 壹哥 开始今天的面试题吧!
请问String类中equals方法的底层是怎么实现的?
说说equals()与==的区别?
2. 题目剖析
上面这个题目,其实考察的还是我们对String类的掌握情况,尤其是对String中两个字符串是否相等的判断,但是这个题目又结合了对Object类中equals()方法的理解。我们看到这个题目,只要打开String类中的equals()方法的源码,就可以得出答案。
二. 佐证案例
1. 代码案例
在讲解今天这个题目的答案之前,我们先来看一段代码,如果我不先给你答案,你能准确说出这几行代码的执行结果吗?
public static void main(String[] args) {
//地址相同
String s1 = "hello world";
String s2 = "hello world";
System.out.println("s1==s2 : " + (s1 == s2));//true
System.out.println("s1.eqauls(s2) : " + s1.equals(s2));//true
//地址不同
String s3 = new String("yiyige");
String s4 = new String("yiyige");
System.out.println("s3==s4 : " + (s3 == s4));//false
System.out.println("s3.equals(s4) : " + s3.equals(s4));//true
//地址不同
String s5 = "syy";
String s6 = new String("syy");
System.out.println("s5==s6 : " + (s5 == s6));//false
System.out.println("s5.eqauls(s6) : " + s5.equals(s6));//true
}
2. 执行结果
好了,我们看看上面这段代码的执行结果,和你预想的结果一样吗?如果一样,说明你的String掌握的很6了,如果有错误,说明你还要再努力啦......
这时候,大家可以结合 壹哥 前面讲解的另外两篇关于String的面试题文章:
《String s=new String("xyz")中产生了几个对象》
《String为什么不可变》
如果你前面仔细看过这两篇文章,其实就可以明白上面的代码为什么是这样的结果了。但是今天我们可以结合String类中的equals()方法,从equals()方法的底层源码角度来进行分析。而且弄明白了equals()方法之后,我们也可以回答另一个面试题,即:请说一下equals()与==的区别。
三. 参考答案
执行完上面的代码案例之后,我们得到了对应的执行结果,但是为什么是这个结果呢?我们来看看String类中equals()方法的底层源码是怎么实现的吧。
1. 底层源码
String类中equals()方法的源码如下:
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
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. 源码分析
我们从上面的源码注释上就可以知道,equals()方法就是用于判断两个字符串是否相同的。但是这个equals()方法对两个字符串是否相同的判断,是根据两个条件进行的,即:
- 两个对象的地址是否向相同;
- equals()方法的参数是不是String类或其父类创建的对象。
2.1 第1个if判断
在equals方法的第一个if判断中,主要是根据"=="符号来判断两个对象的地址是否相同,如果两个对象的地址相同,则直接返回true。比如s1.equals(s2),就在第1个if判断中直接返回true了。
2.2 第2个if判断
在第2个if判断中,出现了instanceof这样的语句,
“anObject instanceof String”
实际上就是判断,该向上转型的对象是不是String的子类或同类,只有是String类型才进行比较。实际上就是判断在上转型之前的那个类型是不是String类型,如果不是,则返回false。如果两个对象都是String类型,则将anObject对象下转型为String类型,然后定义 一个变量n 用来获取value字符数组的长度,我们知道value字符数组中存储的就是当前字符串的字符内容,再接着判断当前字符串的长度与anObject字符串的长度是否相等,因为只有相同才有可能是相同的字符。如果两个字符串的长度不同,这时也会return false。
如果两个字符串的长度相同,则进行下一步判断,进入while循环,一个一个的比较两个字符数组中的字符元素是否相同。如果相同,返回true,如果不同,则返回false。
3. 代码执行分析
我们分析完了equals()方法的源码之后,再结合上面的代码案例,对每一步的执行结果分析一下:
s1==s2:我们知道"=="是用于判断两个对象的地址是否相同的,根据前文可知,s1与s2的地址肯定相同,所以结果为true;
s1.equals(s2):因为s1与s2的地址相同,则在equals()方法的第1个判断中就直接返回true;
s3==s4:因为s3和s4是两个不同的String对象,地址不同,所以结果为false;
s3.equals(s4):在这里会判断s4是否是String类或其子类,然后判断s3与s4对应的字符串内容是否相同,这里s3与s4的地址虽然不同,但是字符串内容相同,所以也是返回true;
s5==s6:两个字符串的地址不同,直接返回false;
s5.equals(s6):最终还是会比较两个字符串的内容是否相同,地址虽然不同,但内容是相同的,所以结果为true。
四. 结论
经过本文的分析,我们就探究了String类中equals()方法的底层源码,明白了其底层执行逻辑,再结合上述案例代码,所以就可以得出如下结论:
String类中equals方法用于比较的两个字符串是否相同。如果两个字符串的地址相同,则直接返回true;如果两个字符串的地址不同,则进一步判断字符串的内容是否相同,字符串内容完全相同,也会返回true。