HashMap的大概数据结构:
HashMap中的put()和get()的实现原理:
map.put(k,v)实现原理
- 首先将k,v封装到Node对象当中(节点)。
- 然后它的底层会调用K的hashCode()方法得出hash值。
- 通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表(哈希碰撞)。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
map.get(k)实现原理
- 先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
- 通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回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重新计算