HashMap 源码分析
特征
- 根据键的 hascode 值存储数据,可直接定位值,具有很快的数据访问数组
- 遍历的顺序不确定
- 最多允许一条 null 键,允许多条记录的键为 null
- 非线程安全
可使用 Collections.synchronizedMap 使 HashMap 具有线程安全的能力 或 ConcurrentHashMap
底层结构
底层结构采用了数组,而数组的每一个元素都是多个 Node 构成的链表,当数组超过 threshold 时,数组将会扩容。
数组中的每一个都相当于一个单向链表,key 通过 hash() 后,相同的键值对会加入到链表中,当桶中的数过多时(链表长度 > 8),将会转化为 红黑树,相比与Jdk 1.7, Jdk 1.8 中当链表过长时,链表转化为红黑树,在维护红黑树时,最坏情况下查找的时间复杂度为 O(log n),比起单链表的 O(1) ~ O(n), 时间复杂度降低了,但所需要维护的空间占用却更多。
1 | // 哈希数组桶,根据 key 的 hashCode 通过 hash() 得到数组下标 |
哈希映射 & 表大小
hash() — 取得 key 的 hashCode 值,依次进行 高位运算,取模运算
tableSizeFor() — 返回大于参数且最接近 2 的整数幂的数值
1 | /** |
扩容
扩容机制实际上就是使用一个更大的数组去 代替 原来的数组,如果原来的数组中存在红黑树 或 链表,则需要把结构重新调整。
对于链表而言, 设计者省略了重新计算新容量下 key 的 hash 值,采用将 hash 值与原容量进行与操作,得到不同的扩展区,两个扩展区分为两条链表。
1 | final Node<K,V>[] resize() { |
存入
1 | public V put(K key, V value) { |
查找
1 | // 查找对应key 的值 |
删除
删除的操作与查找差不多,都是要通过key找到对应的节点,再删除节点
1 | // 删除指定key的值 |
发布于