本文为博主原创,未经允许不得转载:

1. equals 和 hashCode 方法之间的关系

  这两个方法都是 Object 的方法,意味着 若一个对象在没有重写 这两个方法时,都会默认采用 Object 类中的方法实现,它们的关系为:

  1. 如果两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同。

  2. 如果两个对象hashCode相同,不能证明两个对象是同一个对象(不一定相等),只能证明两个对象在散列结构中存储在同一个地址(不同对象hashCode相同的情况称为hash冲突)。

2.为什么重写equals 后需要重写 hashCode

  Effective Java 第三版 中 描述为什么重写equals 方法后必须重写hashCode 方法:

每个覆盖了equals方法的类中,必须覆盖hashCode。如果不这么做,就违背了hashCode的通用约定,也就是上面注释中所说的。
进而导致该类无法结合所以与散列的集合一起正常运作,这里指的是HashMap、HashSet、HashTable、ConcurrentHashMap。

  上面注释 为 Object 类中 hashCode 方法注释:

      If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.

  结论:如果重写equals不重写hashCode它与散列集合无法正常工作。

3. 以 HashMap 为例进行论证分析

  查看 hashMap 的 put 方法

 public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

  查看hash 方法的实现:

  static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

  查看 get 方法的实现:

   public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}

  java中HashMap的数据结构是数组+链表+红黑树;这种数据结构,每个键值对都会被存在相应的地址中,从代码中可以看出HashMap是通过key的hashCode以及自身的容量来决定当前键值的存储索引(桶)的,确定桶的位置后,再进入桶中同时判断hashCode和equals两个方法。那也就是说,如果hashCode不同,那么HashMap就一定会创建一个新的Node键值对象。

  HashMap在put一个键值对时,会先根据键的hashCode和equals方法来同时判断该键在容器中是否已经存在,如果存在则覆盖,反之新建。所以如果我们在重写equals方法时,没有重写hashCode方法,那么hashCode方法还是会默认使用Object提供的原始方法,而Object提供的hashCode方法返回值是不会重复的(也就是说每个对象返回的值都不一样)。所以就会导致每个对象在HashMap中都会是一个新的键。

  反向论证:若一个类中重写了 equals 方法,没有重写hashCode方法;且该类的两个对象具有不同属性但 hashCode 相等,在hashMap 以该对象为键进行存储时,会出现hash冲突现象,但发现该类重写了equals 方法,且通过该类的equals 比较之后也是相等,就会出现 hashMap 中只保存了一个对象,采用get 方法获取时,就会获取到别的对象,从而导致获取对象错乱。

  

  因此 重写equals 方法必须重写 hashCode 方法,用来保证两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同 这一原则;

最新文章

  1. 微软要如何击败Salesforce?Office365、Azure、Dynamics365 全面布局AI | 双语
  2. jQuery 树形菜单
  3. 《objective-c基础教程》学习笔记(九)—— Foundation框架介绍
  4. 如何让Form窗体接收KeyDown事件?
  5. Java IO - BufferedReader &amp; BufferedWriter
  6. cookie使用随笔
  7. LPC2478的SPI使用
  8. c语言入门
  9. drone 1.0 新功能试用以及说明
  10. Spring boot 多模块项目 + Swagger 让你的API可视化
  11. postgresql数据库用户名密码验证失败
  12. 《Python程序设计(第3版)》[美] 约翰&#183;策勒(John Zelle) 第 2 章 答案
  13. javascript 图片上传缩略图预览
  14. 160310、oracle数据库的读写分离
  15. Loki之Funtion
  16. 【BZOJ】4721: [Noip2016]蚯蚓 / 【洛谷】P2827 蚯蚓(单调队列)
  17. 【转载】Java NIO学习 &amp; NIO BIO AIO 比较
  18. git一个系列教程
  19. 在64位SQL Server中创建Oracle的链接服务器 Link Server
  20. 构建maven动态web 工程

热门文章

  1. uoj310. 【UNR #2】黎明前的巧克力
  2. [WPF] 假装可变字体
  3. Java 实现汇总排序
  4. 在Windows11使用WSA运行Google play会遇到的问题
  5. 七牛云简单实用-uploadManager.put(..)抛出异常
  6. JVM的小总结(转)
  7. 说说 RPC 的实现原理?
  8. Container 在微服务中的用途是什么?
  9. springboot-访问数据库
  10. Javascript Range对象的学习