java中的任何类都从老祖宗Object中集成了equals方法,在编程实践中应用使用equals方法判断两个对象是否相同的场景无处不在,所以我们在实现自己的类是必须重写出一个优美的equals方法。
首先让我们来看看java语言规范中对equals方法的说明,一个equals方法应当满足如下几个特性:
自反性,对任何一个非空的引用x,x.equals(x)必须返回true;
对称性,对任何引用x和y来说,如果x.equals(y)返回true,那么y.equals(x)也必须返回true;
传递性,对任何引用x、y和z,如果x.equals(y)为true,y.equals(z)为true,那么x.equals(z)也必须为true;
一致性,如果x和y应用的对象没有发生改变,那么对x.equals(y)的重复调用都应当返回同样的值;
对任何非空引用x,e.equals(null)返回false。
根据上面的6个条件,我们在重写一个equals方法时,可以遵循方法步骤:
将显示参数命名为otherObject,稍后转化为目标类型并命名为other;
检查this和otherObject是否相同;
检查otherObject是否为空,为空则返回false;
检查this和otherObject类型是否相同;
将otherObject转化为目标类型,并命名为other;
对类型中定义的属性进行比较,如果是基础数据类型使用==,如果是引用类型使用equals()。
其中第4条在父子类之间进行比较是需要注意。如果父类中定义的equals中的功能在子类中发生了变化,使用if(this.getClass() != otherObject)进行类型比较;如果父类中equals中的功能在子类中发生了变化,使用if(!(otherObject instanceof this.getClass()))进行比较。例如,Employee类中name和salary两个属性,Manager类继承Employee,还拥有bonus属性。Employee中重写的equals方法比较name和salary是否相同,Manager继承Employee的equals方法后并没有再次进行重写,那么再进行Employee和Manager类的对象的equals比较时,使用 if(!(otherObject instanceof this.getClass()))return false;如果Manager中除了比较name和salary外还要比较bonus,即Manager要重写一个自己的equals方法,那么使用if(this.getClass()!=otherObject.getClass())return false;具体实现可以参考如下代码:
public booleanequals(Object otherObject){//a quick test to see if the object are identical
if(this ==otherObject){return true;
}//must return false if the explicit param is null
if(otherObject == null){return false;
}//if the class des't match, they cannot be equal
if(this.getClass() !=otherObject.getClass()){return false;
}//now we the the otherObject is non-null Employee
Employee other =(Employee)otherObject;//test whether the fields hava identical values
returnname.equals(other.name)&&salary ==other.salary&&hireDay ==other.hireDay;
}
此处有一注意事项,在实现自己的equals方法时,如果声明为public boolean equals(Employee otherObject),即显示参数的类型不是Object类型,那么此方法不是继承自Object对象,而是Employee自己定义的一个方法。从Object继承的public boolean equals(Object otherObject)在java术语中交Overriding,自己定义的public boolean equals(Employee otherObject)叫Overloading。前者在运行期间动态绑定,后者在编译期间静态绑定。