java 覆写equals_《十个为什么》之一:为什么要覆写equals方法与hashCode方法?

先不谈覆写 equals 方法、hashCode 方法的用意,你是否发现自己定义的类很少会覆写 equals 方法、hashCode 方法?——这样看来,这似乎是个冷门的无关紧要的知识,但这也是 Java 基础中不能缺少的一块拼图。

事实上,之所以很少会覆写 equals 方法、hashCode 方法,是因为覆写 equals 方法的目的是为了“找到同类”,它表示一个类中的对象有“逻辑相等”的概念:即是两个对象或许创建的方式或时机不同,它们都是堆内存中分别存在的两个对象,但当他们的成员变量的值完全相同时,则表示它们“逻辑相等”。

只有我们的需求中需要在逻辑上判断两个对象是否相同时,才有必要使用覆写的 equals 方法去判断两个对象是否相等,否则默认的 equals 方法本质上就是两个引用类型的值作“==”比较,此时比较的只是它们的内存地址,故而:即使它们“逻辑相等”,equals 方法判断的结果都是 false。

所以说,如果我根本不需要通过这些方法去“找到同类”,那么不必理会 equals 方法的覆写问题。

其次,object 规范规定,如果要重写 equals 方法,也要重写 hashcode 方法——这很好理解,因为当 equals 比较的结果是 true 时,则两个对象的 hashCode 方法必须返回相同的整数(还有另一句:当 equals 比较的结果是 false 时,则两个对象的 hashCode 方法返回值通常会不同,但有可能相同);而默认的 hashCode 方法是根据内存地址换算出来的值,如果重写了 equals 方法而没有重写 hashcode 方法,那么即使两个对象比较的结果是 true,因为它们的内存地址必然不会相同,hashCode 方法返回的结果不会相同(不清楚底层到底是如何换算的,是否有可能在小概率上会碰到相同的整型结果,暂不可知),显然不符合规范,必须重写hashcode方法使之符合规范。

既然本文标题前缀是十个为什么,就算不是十万个为什么,也应该刨根问底:为什么在有了 equals 方法去判断对象相等的情况下,我们还需要一个 hashCode 方法呢?

显然,上文提到那是规范,但是规范也必然有其存在的原因,私以为是为了在使用到hash算法的工具类中(比如 HashMap)方便使用,立下这个规范,方便相关工具的实现。以 HashMap 举例,它的数据结构是一个以链表为元素的数组,首先根据 hash 值来离散后,能够快速为对象分配位置,当离散值相同时再调用 equals 方法做判断——综合两者的使用,既考虑了性能,也确保了相同对象不会分开存储而导致错误。

顺便,这里也涉及到一个注意点:一个好的 hashCode 方法,应该尽可能让两个不同的对象返回不同的整数,尽量避免散列碰撞。但是,尽管如此,由于 HashMap 的实现机制,并不是直接使用 hashCode 方法返回的整数的(具体看源码),所以不同的 hash 还是会碰撞。由此引申的相关问题,诸如“如何设定 HashMap 的数组大小而避免数组扩容”等,不在本文讨论范围。

综上可知,覆写 equals 方法、hashCode 方法的目的是为了“找到同类”,同时也为涉及hash算法的工具类的性能作考虑。如果你创建的类确实会存在上述情况,那么覆写好 equals 方法、hashCode 方法则是必不可少的工作,否则,它们跟你确实没有啥关系,just forget it……

—— write by NOT IN【 无知无识 无言无闻 】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值