HashMap基于hashing原理,通过put()和get()存储和获得对象。
put(),调用hashCode()获得hashcode,然后找到bucket位置来储存值对象
get(),通过键对象的equals()方法找到正确的键值对,然后返回值对象
(1)什么叫bucket?
当系统开始初始化 HashMap 时,系统会创建一个长度为 capacity 的 Entry 数组,这个数组里可以存储元素的位置被称为“桶(bucket)”,每个 bucket 都有其指定索引,系统可以根据其索引快速访问该 bucket 里存储的元素。
- capacity为当前HashMap的Entry数组的大小,Entry数组的大小是2的N次方
- threshold为HashMap的size最大值,注意不是HashMap内部数组的大小。
threshold = (int)(capacity * loadFactor);
存储示意
(2)什么是负载因子(load factor)
当创建 HashMap 时,有一个默认的负载因子(load factor),其默认值为 0.75,这是时间和空间成本上一种折衷:增大负载因子可以减少 Hash 表(就是那个 Entry 数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的的操作(HashMap 的 get() 与 put() 方法都要用到查询);减小负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间。
(3)HashMap的碰撞问题
不同的键对象有相同的hashcode值时,会发生碰撞,使用单向链表解决碰撞问题。它们会储存在同一个bucket位置的链表中。
当冲突发生时,使用某种探查技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定的地址。
按照形成探查序列的方法不同,可将开放定址法区分为线性探查法、二次探查法、双重散列法等。
(4)HashMap 的读取实现
当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value 即可。如果发生了碰撞问题,单个 bucket 里存储的不是一个 Entry,而是一个 Entry 链,系统只能必须按顺序遍历每个 Entry,直到找到想搜索的 Entry 为止——如果恰好要搜索的 Entry 位于该 Entry 链的最末端(该 Entry 是最早放入该 bucket 中),那系统必须循环到最后才能找到该元素。
原文链接:https://blog.csdn.net/wenyiqingnianiii/article/details/52204136