首先你肯定是要先介绍一下hashmap是什么
介绍
数据结构部分
- 键值都允许null
- 非线程安全
- 它的key是无序的。
HashMap的数据结构是什么?(HashMap如何解决哈希冲突,还有什么方法)
这个问题可以从两个方面来解释
数据底层具体存储的是什么:HashMap是一个用来存储Key-Value的键值对集合,Java中HashMap采用了链地址法。链地址法,简单来说,就是数组加链表的结合。每个数组元素都是一个链表结构,当数据被Hash后,得到数组下标,把数据放在对应下标元素的链表上。所以它底层的数据结构是数组+链表,JDK1.8增加了红黑树部分。链表的每一个节点都会保存自身的hash、key、value、以及下个节点地址
这样的存储方式有什么优点:Hash解决冲突的办法主要有两种类型:
一是封闭散列,比如开放地址法:基本思想是所有的记录都存储在数组中,当在p位置发生哈希冲突时,会以p位置为基准通过探测序列找到一个不冲突的哈希地址。
它的优点在于,如果记录总数可以预知,可以创建完美哈希函数,此时处理数据的效率是非常高的。它的缺点很明显,1.扩容效率低会导致某次操作的时间成本飙升2.删除时只能在删除的节点上做标记,而不能真正删除节点,,因为如果删除节点,会导致与该位置冲突的后续节点无法查询。总的来说就是对于频繁插入和删除的操作比较复杂和耗时。
二是开放散列,链地址法:基本思想就是数组加链表的结合。每个数组元素都是一个链表结构,当数据被Hash后,得到数组下标,把数据放在对应下标元素的链表上。
它的优点在于对于记录总数频繁可变的情况,处理的比较好,删除记录时,比较方便,直接通过指针操作即可。它的缺点在于哈希表的跳转访问会带来额外的时间开销,JDK1.8之后引入了引入了红黑树,当链表长度太长(默认超过8)时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能。
主要参数
- Node<K,V>[] table:初始化长度length(默认值是16)
- loadFactor:负载因子(默认值0.75)
- threshold:是HashMap所能容纳的最大数据量的Node(键值对)个数。threshold = length * Load factor。也就是说,在数组定义好长度之后,负载因子越大,所能容纳的键值对个数越多。
- size:HashMap中实际存在的键值对数量。(与table的长度区分)
为什么是16?
我觉得应该是一个经验值,它在源码中的表示是写成1左移运算符4,而不是16我觉得就是一种提示,只要是2次幂,其实用 8 和 32 都差不多。
Hash算法(hashmap 长度2的幂次方原因)
java中建议初始化hashmap的时候设置一个尽量接近真实情况的二次幂方。这有两个原因:
- java会根据用户传入的容量值,通过计算,得到第一个比他大的2的幂。直接给一个二次方会节省这个计算搜索时间
- 避免不必要的扩容过程
这与hashmap的定位算法相关。
hash算法的目标是元素位置尽量分布均匀,尽量避免发生哈希冲突。
return (key == null) ? 0 : (h = key.hashCode()) ^ (h &g