Object.equals重写,判断对象相等
Object.equals方法用于检测一个对象是否等于另外一个对象。在Object类中,这个方法将判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,它们一定是相等的。
下面对普通的Java类重写.euqals方法,用于判断两个类是否相等(值相等)。
编写一个完美equals方法的建议:
1. 显示参数命名为otherObject,稍后需要将它转换成另外一个叫做other的变量。
2. 检测this与oterObject是否引用同一个对象:
if (this == otherObject) return true;
这条语句只是一个优化。实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中的域所付出的代价小很多。
3. 检测otherObject是否为null,如果为null,返回false。这项检查是很有必要的。
if (otherObject == null) return false;
4. 比较this与otherObject是否属于同一个类。
a. 如果子类能够拥有自己相等的概念,则对称性需求强制采用getClass进行检测。
b. 如果由超类决定相等的概念,只要超类中对应的域相等,就认为两个对象相等,那么就可以使用instanceof进行检测(instanceof 父类),这样可以在不同子类的对象之间进行相等的比较。并且应该将超类中的Employ.equals声明为final,子类无法覆盖这个方法。
c. 如果equals的语义在每个子类中有所改变,就使用getClass检测:
if (getClass != otherObject.getClass) return false;
如果所有的子类都拥有统一的语义,就是用instance检测:
if (! (otherObject instance of ClassName)) return false; // ClassName为父类
5. 将otherObject转换为相应的类类型变量:
ClassName other = (ClassName) otherObject;
这是因为:
如果otherObject声明为父类对象,如Object超类对象,无法访问子类中的域,也需要进行类型转换。(最常见情况)
如果otherObject声明为子类对象,无法访问父类中的私有域,从而要进行类型转换。
6. 现在开始对所有需要比较的域进行比较。使用==比较基本类型域,使用Objects.equals比较对象域。如果所有的域都匹配,就返回true;否则返回false。
return field1 == other.field
&& Objects.equals(field2, other.field2)
&& ...;
示例:
Employee.java 类文件:
import java.time.*;
import java.util.Objects;
public class Employee
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year, int month, int day)
this.name = name;
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
public String getName()
return name;
public double getSalary()
return salary;
public LocalDate getHireDay()
return hireDay;
public void raiseSalary(double byPercent)
double raise = salary * byPercent / 100;
salary += raise;
public boolean equals(Object otherObject) {
// test if the objects is identical
if (this == otherObject) return true;
// the explicit parameter is null;
if (otherObject == null) return false;
// if the classes don't match, they can't be equal
if (getClass() != otherObject.getClass()) return false;
// test getClass() and otherObject.getClass()
System.out.println("getClass is: " + getClass());
System.out.println("otherObject.getClass is: " + otherObject.getClass());
// now we know otherObject is a non-null Employee
Employee other = (Employee) otherObject;
return Objects.equals(name, other.name) // name may be null
&& salary == other.salary
&& Objects.equals(hireDay, other.hireDay); // hireDay may be null
注意:.equals方法的覆盖,为了避免发生类型错误,可以使用@Override对覆盖的超类方法进行标记。
/**
* 这个方法声明的显示参数类型是Employee。其结果并没有覆盖Object类的equals方法,而是定义了一个完全无关的方法。
* 为了避免发生类型错误,可以使用@Override对覆盖的超类方法进行标记。
* 如果出现了错误,并且正在定义一个新的方法,编译器就会给出错误报告。
* 例如:@Override public boolean equals(Employee otherEmployee)
* 就会看到一个错误报告Method does not override method from its superclass。
* 这是因为这个方法并没有覆盖超类Object中的任何方法。
@Override
public boolean equals(Employee otherEmployee) {
// test if the objects is identical
if (this == otherEmployee) return true;
// the explicit parameter is null;
if (otherEmployee == null) return false;
// if the class is don'n match, they can't be equal
if (getClass() != otherEmployee.getClass()) return false;
System.out.println("getClass is: " + getClass());
System.out.println("otherObject.getClass is: " + otherEmployee.getClass());
// now we know otherObject is a non-null Employee
Employee other = (Employee) otherEmployee;
return Objects.equals(name, other.name) // name may be null
&& salary == other.salary
&& Objects.equals(hireDay, other.hireDay); // hireDay may be null
}
Manager.java 类文件:
public class Manager extends Employee
private double bonus;
* @param name the employee's name
* @param salary the salary
* @param year the hire year
* @param month the hire month
* @param day the hire day
public Manager(String name, double salary, int year, int month, int day)
super(name, salary, year, month, day);
bonus = 0;
public double getSalary()
double baseSalary = super.getSalary();
return baseSalary + bonus;
public void setBonus(double b)
bonus = b;
public boolean equals(Object otherObject) {
* super.equals checked that this and otherObject belongs to the same class.
* 子类中定义equals方法时,首先调用超类的equals,比较从超类中继承的域。
* 如果检测失败,对象就不可能相等。如果从超类中继承的域都相等,就需要比较子类中定义的实例域。
if (! super.equals(otherObject)) return false;
Manager other = (Manager) otherObject;
return bonus == other.bonus;
}
Main.java 类文件:
public class Main {
public static void main(String[] args)
// construct a Manager object
Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
Manager boss1 = new Manager("Carl", 80000, 1987, 12, 15);
boss.equals(boss1); // 输出: getClass is: class com.qjq.demo.Manager
// otherObject.getClass is: class com.qjq.demo.Manager
boss.setBonus(5000);
Employee[] staff = new Employee[3];
// fill the staff array with Manager and Employee objects
staff[0] = boss;
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
staff[2] = new Employee("Harry Hacker", 40000, 1990, 3, 15);
System.out.println(boss.getClass()); // class com.qjq.demo.Manager
System.out.println(staff[0].getClass()); // class com.qjq.demo.Manager
System.out.println(staff[1].getClass()); // class com.qjq.demo.Employee
System.out.println(staff[1].equals(staff[2])); // false
System.out.println(staff[0] instanceof Manager); // true
* staff[0].setBonus(500); // 报错
* 虽然staff[0]和boss引用同一个Manager对象,
* 但是,staff[0]声明的类型是Employee,编译器将staff[0]看成Employee对象,而setBonus不是Employee的方法。
* 如果要通过staff[0]调用其引用的setBonus方法,只能在继承层次内进行类型转化。
boss.setBonus(100);
* 只能在继承层次内进行类型转换;
* 在将超类转换成子类之前,应该使用instanceof进行检查;
* 转换失败时,Java不会生成一个null对象,而是抛出一个异常。所以要先进行instanceof判断,再进行雷翔转换。
* 等价于C++中的引用转化:
* Manager* boss = dynamic_cast<Manager*>(staff[0])
* if (boss != NULL) ...
* dynamic_cast转换失败后,boss为NULL。
if (staff[0] instanceof Manager) {
Manager boss_ = (Manager) staff[0];
boss_.setBonus(500);
// print out information about all Employee objects
for (Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
}
对于数组类型的域,可以使用静态的Arrays. equals方法检测相应的数组元素是否相等。
如果两个数组长度相同,并且对应的位置上数据元素也均相同,则返回true。数组的元素类型可以是Object, int, long, short, char, byte, boolean, float, double。
int[] intArray = new int[2];
int[] intArray1 = new int[2];
for (int i = 0; i < 2; i++) {
intArray[i] = i;
intArray1[i] = i;
System.out.println(Arrays.equals(intArray, intArray1));
Tips: 如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。
public int hashCode() {
return 7 * name.hashCode()
+ 11 * new Double(salary).hashCode()
+ 13 * hireDay.hashCode()
// 或者
public int hashCode() {
return 7 * Objects.hashCode(name) // 使用Objects.hashCode,对象null情况下安全,参数为null返回0
+ 11 * Double.hashCode(salary) // 使用静态方法Double.hashCode避免创建Double对象
+ 13 * Objects.hashCode(hireDay)