为什么重写Equals方法要重写HashCode方法
1.Equals的作用和重写Equals需要遵循的规则
Equals的主要作用是判断两个对相是否相等, Object类是所有类的父类,因此每个对象都可以使用Object的Equals相比较:
public boolean equals(Object obj) {
return (this == obj);
}
- Object类中equals方法比较的是两个对象的引用地址,只有对象的引用地址指向同一个地址时,才认为这两个地址是相等的,否则这两个对象就不想等。
- 如果有两个对象,他们需要的是这两个对象相等,因此默认的equals()方法是不符合我们的要求的,这个时候我们就需要对equals()方法进行重写以满足我们的预期结果。
- 在java的集合框架中需要用到equals()方法进行查找对象,如果集合中存放的是自定义类型,并且没有重写equals()方法,则会调用Object父类中的equals()方法按照地址比较,往往会出现错误的结果,此时我们应该根据业务需求重写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;
- 除非对象被修改,否则调用多次equals应为同样结果:对于任意的对象x和y,x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也均为true,前提条件是没有修改x也没有修改y;
- 对于非空引用x,x.equals(null)永远返回为false。
2.重写hashcode的原因及重写hashCode()方法需要遵循的协定
1.什么是hashcode
hashcode是一个数值,主要作用是散列数据的快速存储, Object类是所有类的父类,因此每个对象都可以使用Object的hashcode()得到对应的hash值:
public native int hashCode();
- hashCode()方法用于散列数据的快速存储,HashSet/HashMap/Hashtable类存储数据时都是根据存储对象的hashcode值来进行分类存储的,一般先根据hashcode值在集合中进行分类,在根据equals()方法判断对象是否相同。
- HashMap对象是根据其Key的hashCode来获取对应的Value。
- 生成一个好的hashCode值能提高HashSet查找的性能,差的hashCode值不但不能提高性能,甚至可能造成错误。比如hashCode方法中返回常量,会让,HashSet的查找效率退化为List集合的查找效率;hashCode方法中返回随机数,会让查找结果变的不可预测。
- 好的hashCode生成方式是让对象中的关键属性与质数相乘,并将积相加获取。
2.重写hashcode方法的原因:
- 为了维护hashCode()方法的equals协定,该协定指出:如果根据 equals()方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode方法都必须生成相同的整数结果;而两个hashCode()返回的结果相等,两个对象的equals()方法不一定相等。
- HashMap对象是根据其Key的hashCode来获取对应的Value。
- 在重写父类的equals()方法时,也重写hashcode()方法,使相等的两个对象获取的HashCode值也相等,这样当此对象做Map类中的Key时,两个equals为true的对象其获取的value都是同一个,比较符合实际。
3.重写hashCode()方法需要遵循的协定
- 一致性:在Java应用程序执行期间,在对同一对象多次调用hashCode方法时,必须一致地返回相同的整数,前提是将对象进行hashcode比较时所用的信息没有被修改。
- equals:如果根据equals()方法比较,两个对象是相等的,那么对这两个对象中的每个对象调用hashCode()方法都必须生成相同的整数结果,等价对象必须有相同的hashcode。注:这里说的equals()方法是指Object类中未被子类重写过的equals()方法。
- 如果根据equals()方法比较,两个对象不相等,那么对这两个对象中的任一对象上调用hashCode方法不一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
示例代码
学生类: Student.java
package com.java.example;
import java.util.Objects;
public class Student {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Student student = (Student) obj;
return this.age == student.age && Objects.equals(this.age, student.age) && Objects.equals(this.name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(this.age, this.name);
}
}
测试类: EqualsAndHashcode.java
package com.java.example;
import java.util.HashSet;
public class EqualsAndHashcode {
public static void main(String[] args) {
Student student1=new Student(23,"李四");
Student student2=new Student(23,"李四");
System.out.println(student1==student2);
System.out.println(student1.equals(student2));
HashSet<Student> set=new HashSet<>();
set.add(student1);
set.add(student2);
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
System.out.println(set.size());
}
}
【参考资料】
https://blog.csdn.net/qq_45830276/article/details/126615786
https://baijiahao.baidu.com/s?id=1746705951468143428&wfr=spider&for=pc
https://blog.csdn.net/wdnn_wza/article/details/125075525
https://blog.csdn.net/WinnerBear/article/details/126068645