HashMap存值、取值及哈希碰撞原理分析

590 阅读2分钟

HashMap的大概数据结构:

image.png

HashMap中的put()和get()的实现原理:

map.put(k,v)实现原理

  1. 首先将k,v封装到Node对象当中(节点)。
  2. 然后它的底层会调用K的hashCode()方法得出hash值。
  3. 通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表(哈希碰撞)。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。

map.get(k)实现原理

  1. 先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
  2. 通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。

为何随机增删、查询效率都很高的原因是?

原因: 增删是在链表上完成的,而查询只需扫描部分,则效率高。

注: HashMap集合的key,会先后调用两个方法,hashCode and equals方法,这这两个方法都需要重写。

为什么放在hashMap集合key部分的元素需要重写equals方法?

因为equals方法默认比较的是两个对象的内存地址


哈希碰撞概述

  • 在调用HashMap的put(key k,value v)方法时,若key的哈希值相等了,则发生哈希碰撞(冲突);
  • 此时,若equals()比较相等,则表示key相同,判断元素相同,会执行覆盖操作;若equals()不相等,则形成链表,追加到链表末尾;
  • 当链表长度等于8时,优化为红黑树结构(jdk1.8开始优化为红黑树),当调用remove(key k)方法删除元素时,剩余6个的时候,退回链表结构;

如何避免哈希碰撞

避免哈希碰撞,就要尽量让key的hash值不相同,key的hash值和map的容量有很大关系,容量越大越不容易发生碰撞。

所以避免哈希碰撞的有效方式就是:扩容, 当map扩容后,size发生改变,所有的key的hash值,都会通过reHash重新计算