重写equals为什么要重写hashCode

发布时间 2023-07-24 16:30:54作者: 风筝上的猫

我们知道一旦重写了equals方法,就一定要重写hashCode方法。为什么?

------因为必须保证重写后的equals方法认定相同的两个对象拥有相同的哈希值
------当我们将equals方法重写后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中“相同对象必须有相同哈希值”的约定。
 
那么怎样去解释这句话?接着往下看。
 
我们打开Object类的equals方法源码,可以看到有一部分注释是这样写的:
大致意思是:每当重写 equals方法后, hashCode 方法通常也需要重写,以便维护 hashCode 方法的一般协定,该协定声明相等的对象必须具有相等的哈希值
 
那为什么要去维护 hashCode 方法的协议呢?找到hashCode方法源码,这里给出了解释:
 
首先hashCode方法相当于一个哈希函数,将对象的内部地址转换为一个integer类型的哈希值。
 
hashCode总的契约有三条,分别是:
   1、一个对象多次调用他的hashCode应该返回相同的整数(哈希值);
   2、如果两个对象根据equals方法判断是相等的,那么这两个对象返回的整数也应该相同;
   3、如果两个对象根据equals判断是不相等的,不要求返回不同的整数,但不同的整数结果对应的对象也应该是不同的。
 
以画图的方式表示这三条契约:
 
 equals方法和hashCode方法两者的关系,总结一下就是:
  1. 如果两个对象相同(equals返回true),那么他们的hashCode值一定相同;
  2. 如果两个对象不同(equals返回false),那么他们的hashCode值可能相同可能不同;
  3. 如果两个对象的hashCode值相同(hash冲突),那么他们可能相同也可能不同(equals方法返回false / true);
  4. 如果两个对象的hashCode值不同,那么他们肯定不同(equals返回false)。

其实到这里,我们就明白equals方法与hashCode方法是配套使用的。对于任何一个对象,不论是使用继承自Object的equals方法还是重写equals方法。hashCode方法实际上必须要完成的一件事情就是,为该equals方法认定为相同的对象返回相同的哈希值

 

⭕还要注意一点就是,当重写equals方法时通常将hashCode方法重写,提高比较效率。

(例如先求hashCode值,如果相等 再使用equals比较,比起用equals挨个比较块且便捷)

 

以上就是理论内容,下面举个例子
 
 
问题一:我对左侧QueryBO的equals方法和hashCode方法进行了重写,在右边的比较中应该输出什么?
 
-----true
-----原因:如果不重写equals,那么只有两对象内所有属性都相同才认为相等;而现在我重写了equals,这里只需要对象的query3相等,则认为两对象想等。
 
问题二:将queryBO1对象和queryBO2放进Set集合,Set集合中有几个对象?
 
-----1个
-----由于上一步判定两对象相等,而Set集合中的元素是不重复的,所以Set中只有一个元素。
Set<QueryBO> set=new HashSet<>();
set.add(queryBO1);
set.add(queryBO2);
System.out.println("Set:"+set);
//输出 Set:[QueryBO(query1=true, query2=true, query3=false)]

 

问题三:将代码更改,再次进行上述两步操作,这次的答案又是什么

输出:

Set:[QueryBO(query1=true, query2=true, query3=false), QueryBO(query1=false, query2=true, query3=true)]
true

-----为什么equals比较结果为true,但去重集合Set中却有两个元素呢?

-----原因:像HashSet、HashMap这类 判断两对象相不相同先比较的是hashCode( ),equals比较的是query2,而hashCode比较的是query3,hashCode不相等了,所以我们的HashSet也会认为两个对象不相等。

 

所以注意 重写equals( )一定要重写hashCode( ) !

 

 问题四:字符串的hashCode相等,这两个对象一定相等吗?(hashCode相等的字符串一定相等?)

-----错。hashCode相等两个字符串不一定相等。

-----例子:一下这些字符串的hashCode都一样。