hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。
equals()
默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。
hasCode()
hashCode()方法返回的就是一个数值,从方法的名称上就可以看出,其目的是生成一个hash码
代码实现
创建一个简单的User类;
import java.util.Objects;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
现在比较两个User类对象是否相等;
public class hashCodeAndEquals {
public static void main(String[] args) {
User a=new User();
User b=new User();
a.setId(10);
b.setId(10);
System.out.println(a.equals(b));
//输出false
}
}
上面会输出false,如果真实情况下,我们希望得到的是true。
所以,需要重写equals()方法。(IDEA中自带覆写方法,可以借鉴)
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id;
}
之后结果就为true。
换一种测试方法,用hashSet测试,看是否相等;
package test;
import java.util.HashSet;
import java.util.Set;
public class hashCodeAndEquals {
public static void main(String[] args) {
User a=new User();
User b=new User();
a.setId(10);
b.setId(10);
System.out.println(a.equals(b));
//true
Set<User> users=new HashSet<>();
users.add(a);
users.add(b);
System.out.println(users);
//[test.User@4554617c, test.User@1b6d3586]输出了两个值
}
}
显然,equals返回true,Set中不允许出现相同的Key,所以出错了,why?
因为忘记了hasCode方法。
@Override
public int hashCode() {
return Objects.hash(id);
}
//之后的运行结果为[test.User@29]
得出结论:重写equals就得重写hasCode。
equals()和hashCode()的关联
如果两个对象相等,则hashcode一定也是相同的
两个对象相等,对两个对象分别调用equals方法都返回true
两个对象有相同的hashcode值,它们也不一定是相等(equals)的
因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
为什么覆盖equals时总要覆盖hashCode
在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap、HashSet和Hashtable。
因为如果不覆盖equals方法的话,相等的对象可能返回的不相同的hash code。
比如:
一个对象修改equals,判断里面的字段是否一致即相等,但是没有修改hasCode
hashmap中的key根据hashCode分配到不同的元素,但是用equals尝试,key却是相等的,会出现很多异常bug.
需要记住的事情
1.尽量使用对象的同一个属性来生成hashCode()和equals()。如,在案例中使用id。
2.eqauls方法必须保证一致(如果对象没有被修改,equals应该返回相同的值)。
3.任何时候只要a.equals(b),那么a.hashCode()必须和b.hashCode()相等。
4.两者必须同时重写。
对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
这种大量的并且快速的对象对比一般使用的hash容器中,如:hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。
部分相关原文链接:https://blog.csdn.net/gyshun/article/details/80852278