参加VIVO秋招面试中,在回答「Object类有哪些方法?每个方法分别有什么作用?」问题时,提到equals()方法,就又被问到 「在重写equals()方法需要注意什么?」,顿时就一脸懵逼,这也是面试「Java开发工程师」过程中的高频问题,在此进行一个系统的总结与梳理。
参考答案
为什么要重写equals()方法?
Object类中equals()方法的默认实现主要是用于判断两个对象的引用是否相同。而在实际开发过程中,通常需要比较两个对象的对应属性是否完全相同,故需要重写equals()方法。
如何重写equals()方法?
假设equals()方法的形参名为otherObj,稍后需要将其转换为另一个叫做other的变量。
第一步,检测this与otherObj是否引用同一对象:
if(this == otherObject) return true;
第二步,检测otherObj是否为空:
if(otherObject == null) return false;
第三步,判断this与otherObj是否属于同一个类,具体分两种情况:
(1). 如果equals()方法的语义在每个子类中均有所改变,则使用getClass()方法进行检测:
if(getClass() != otherObject.getClass()) return false;
(2). 如果equals()方法在所有子类中均有统一的语义,则使用instanceof关键字进行检测:
if (!(otherObject instanceof ClassName)) return false;
第四步,将otherObj转换为相应类的类型变量:
ClassName other = (ClassName) otherObject;
第五步,对所有需要比较的域进行一一比较,若全匹配则返回true,否则返回false。
关于equals()语义的补充说明:假设现有Employee与Manager两个类,Manager类继承Employee类。若仅将ID作为相等的检测标准,则仅用在Employee类中重写equals()方法,并将该方法声明为final的即可,这就是所谓的「拥有统一的语义」。
重写equals()方法需要注意什么?
归根结底,还是想问equals()方法的主要特性。Java语言规范要求equals()方法具有如下特性:
- 自反性:对于任何非空引用x,x.equals(x)应该返回true。
- 对称性:对于任何引用x和y,当且仅当y.equals(x) 返回true时,x.equals(y)也应该返回true。
- 传递性:对于任何引用x、y和z,如果x.equals(y) 返回true,y.equals(z)返回true,x.equals(z)也应该返回true。
- 一致性:如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果。
- 非空性:对于任何非空引用x,x.equals(null)应该返回false。
源码阅读
// Object类中equals()方法的默认实现
public boolean equals(Object obj) {
return (this == obj);
}
// String类中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;
}