java 的 equals 方法一般情况下需要重写,以保证能够比较两个实例对象是否一致,注意重写 equals 方法时还要重写 hashCode 方法。
equals 方法的注意事项:1)方法 equals 应为继承自 Object 的方法(可用 @Override 标示)。2)如果子类要重写此方法,在最后判断时同样要先调用父类方法 equals 判断父类中数据是否相等。3)方法 equals 中比较的内容应有序、完整。4)应重写 hashCode 方法。
下面以 Employee 类为例介绍(Cloneable 接口在此可忽略):
package ch05;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Objects;
/**
* @author qiaowei
*
*/
public class Employee implements Cloneable {
public Employee(String name, double salary) {
GregorianCalendar calendar = new GregorianCalendar();
mName = name;
mSalary = salary;
mHireDay = calendar.getTime();
}
public Employee(String n, double s, int year, int month, int day) {
mName = n;
mSalary = s;
GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
mHireDay = calendar.getTime();
}
@Override
public boolean equals(Object o) {
/**
* equals must five steps:
* 1:two variable are point to the same object.
* 2:obj is null.
* 3:variables is the same Class.
* 3.5: use instanceof test.
* 4:cast obj.
* 5:equals each field's value(== for primitive; equals for object).
* */
if (this == o) {
return true;
}
if ((null == o) ||
(this.getClass() != o.getClass())) {
return false;
}
if ( !(o instanceof Employee)) {
return false;
} else {
Employee e = (Employee)o;
/*return ((mName.equals(e.getName()) &&
mSalary == e.getSalary()) &&
mHireDay.equals(e.getDate()));*/
//类类型用Objects.equals方法比较,基础类型用==比较
return (super.equals(e)) &&
(Objects.equals(mName, e.getName()) &&
mSalary == e.getSalary() &&
Objects.equals(mHireDay, e.getDate()));
}
}
@Override
public int hashCode() {
//以下两种方法都可正确
/*return (7 * Objects.hashCode(name) +
11 * new Double(salary).hashCode() +
13 * Objects.hashCode(hireDay));*/
return Objects.hash(mName,
mSalary,
mHireDay);
}
//实现Cloneable接口
@Override
public Employee clone() throws CloneNotSupportedException {
Employee cloned = (Employee)super.clone();
cloned.mName = mName;
cloned.mSalary = mSalary;
cloned.mHireDay = (Date)mHireDay.clone();
return cloned;
}
public final String getName() {
return mName;
}
public double getSalary() {
return mSalary;
}
public Date getDate() {
return (Date)mHireDay.clone();
}
public void raiseSalary(double byPercent) {
double raise = mSalary * byPercent / 100;
mSalary += raise;
}
private String mName;
private double mSalary;
private Date mHireDay;
}
Manager 类(Employee 的子类)重写 equals 和 hashCode 方法:
package ch05;
import java.util.Objects;
/**
* @author qiaowei
* 重写类的equals方法,在重写同时需重写hashCode方法
*/
public class Manager extends Employee{
public Manager(String n, double s, int year, int month, int day) {
super(n, s, year, month, day);
mBouns = 0;
}
@Override
public boolean equals(Object otherObj) {
//首先比较基类是否一致
if ( !super.equals(otherObj)) {
return false;
}
if (this == otherObj) {
return true;
}
if (null == otherObj) {
return false;
}
if (getClass() != otherObj.getClass()) {
return false;
}
if ( !(otherObj instanceof Manager)) {
return false;
} else {
Manager manager = (Manager)otherObj;
/*return (manager.getName() == getName() &&
manager.getSalary() == getSalary() &&
manager.getDate() == getDate() &&
manager.bonus == bonus);*/
//注意父类数据同样要判断是否相等
return (mBouns == manager.mBouns);
}
}
@Override
public int hashCode() {
/*return (super.hashCode() +
17 * new Double(mBouns).hashCode());*/
//父类数据同样要用hash
return Objects.hash(super.hashCode(), mBouns);
}
public static void main(String[] args) {
Manager m01 = new Manager("jowei000", 1000, 1981, 2, 5);
Manager m02 = new Manager("jowei000", 1000, 1981, 2, 15);
//比较实例是否相等
//System.out.println(m01.equals(m02));
System.out.println(m01.hashCode());
System.out.println(m02.hashCode());
}
private double mBouns;
}
20230529:注意在基类、子类的方法 equals 中都使用 “instanceof” 关键字,关键字 instanceof 判断变量是否能转换成对应类,所以变量可能是对应类,也可能对应的是基类,所以关键字 instanceof 并不能准确判断是否是对应的类型。所有不建议使用。