HashCode()和equals()方法详解

这两个方法的问题一直困扰了我很久。不清楚他们各自的用处和实现,记得在实习的时候遇到过一个问题:将自定义的对象放在一个set集合中,目的是筛选出不重复的对象集合,但是结果却是错误的。比如说有10个对象,但是其中有两个是相等的,那么期望的set的大小应该是9,但是最终结果却是10。让我很奇怪,后来带我的师傅说了一句话:需要重写类中的hashCode()和equals()方法。我还是一头雾水,最近才研究了一个这两个方法,总结一下。

 

Java中HashCode()和equals()方法是Object中的,所以每个对象都有这两个方法。 equals()和hashCode()方法是用来在同一类中做比较用的,尤其是在容器里如set存放同一类对象时用来判断放入的对象是否重复。

 

首先我们需要搞清楚一个问题:

equals()相等的两个对象,hashCode()一定相等;equals()不相等的两个对象,hashCode()可能相等也可能不等。反过来:hashCode()不相等,他们的hashCode()一定不相等;hashCode()相等,equals()不一定相等。举一个例子比较形象,hashCode()就像字典里的索引,equals()就像字典中同一个字下的不同的词语,“自己”和“自发”这两个词的索引“自”是一样的(hashCode),但是却是不相等的(equals)。

 

在Object类中,hashCode()是本地方法,返回的是对象的地址值,而Object类中equals()返回的也是地址值。

 

值得一提的是,hash算法对于查找元素提高了效率。如果想要在一个集合中找到你想要的元素,通常的做法是遍历整个集合,取出每个对象比较是否是你想要的,找到则返回。但是当集合足够大时,这种做法的平均时间是很长的(性能低)。有人发明了一种哈希算法,这种方法将集合分成几个若干的存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组(根据相同的函数计算哈希码),每个组对应一个存储空间,那么查找一个对象的时候,先计算他的哈希码就可以先确定他是在那个存储区域的,然后只需要在这个区域遍历比较即可;插入一个元素的时候,也先计算他的哈希码,确定存储区域,再在该存储区域添加该元素。Object类中定义的hashCode()方法就是返回每个对象的哈希码,当从hashSet集合中查找一个对象时,java系统首先对象的hashCode()获取该对象的哈希码表,然后根据哈希码找到对应的存储区域,最后取得该存储区域的每个元素与该对象进行equals()比较。可以看出,HashCode对于查找元素有着较高的性能,但是插入元素时,效率相对低些。 因为向HashSet集合中添加一个对象时,要先计算出对象的哈希码和根据这个哈希码确定对象在集合中的存放位置为了保证一个类的实例对象能在HashSet正常存储,要求这个类的两个实例对象用equals()方法比较的结果相等时,他们的哈希码也必须相等;也就是说,如果obj1.equals(obj2)的结果为true,那么以下表达式的结果也要为true:

obj1.hashCode() == obj2.hashCode()

换句话说:当我们重写一个对象的equals方法,就必须重写他的hashCode方法,不过不重写他的hashCode方法的话,Object对象中的hashCode方法始终返回的是一个对象的hash地址,而这个地址是永远不相等的。所以这时候即使是重写了equals方法,也不会有特定的效果的,因为hashCode方法如果都不想等的话,就不会调用equals方法进行比较了,所以没有意义了。

 

看到这里就应该明白刚开始的问题,自定义的对象的hashCode()返回的是每个对象的地址值,永远不会相等,因此在放入hashSet中时,hashCode()不等,就不会比较equlas()方法了,因此都不会被放入set中。 Object类中的hashCode()方法不能满足对象被存入到HashSet中的要求,因为它的返回值是通过对象的内存地址推算出来的,同一个对象在程序运行期间的任何时候返回的哈希值都是始终不变的,所以,只要是两个不同的实例对象,即使他们的equals方法比较结果相等,他们默认的hashCode方法的返回值是不同的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值