HashMap源码分析笔记

参考笔记

底层:数组+链表+红黑树

重点

  1. 扰动函数
java 复制代码
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

key的哈希值进行扰动:高16位不变,低16位和高16位做异或运算,赋值给低16位。目的是在数组长度较短的时候减少冲突。

  1. 存放位置的计算
    根据key的哈希值,计算出在数组中存放的位置。
java 复制代码
hash & (length - 1)

实际就是取模,hash%length,计算机中直接求余效率不如位移运算,源码中做了优化hash&(length-1)。要想保证hash%length==hash&(length-1),那么length必须是2的n次方;

  1. 添加元素的方法
java 复制代码
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)
  1. 扩容方法
java 复制代码
final Node<K,V>[] resize()
  • 当哈希表中的元素个数达到了扩容阈值threshold,就进行扩容。

  • 为什么需要扩容?当元素越来越多的时候,hashMap的查找速度就从O(1)升到O(n),导致链化严重。为了解决冲突带来的查询效率的下降,因此需要扩容。

    1. 初始化扩容。

      ①没有指定capacity。则给定默认值capacity = 16threshold = 12。如果调用new HashMap(); 此时,哈希表的容量和扩容阈值都为0。则给他们赋初值。没有指定大小,默认为16。扩容阈值默认16*0.75。其中,0.75是默认的负载因子。

      ②指定了capacity。通过tableSizeFor方法获取第一个大于等于capacity的2的次方数,并赋值给threshold。分配内存时,通过threshold 大小分配内存。(capacity 哈希表的长度,没有分配内存时,长度为0。)

    1. 非初始化扩容。threshold和数组大小都变为原来的2倍。

对链表进行分解

扩容后数组的长度是原来的2倍。链表的元素需要重新计算存放位置。链表会被分为两个部分。

一部分位于原来位置,另一部分转移到新位置。新位置 = 老位置 + 老数组长度。

  1. tableSizeFor方法
java 复制代码
// 此方法核心功能就是求出,大于等于输入长度的2次幂的值
// 如输出:8,输出为8
// 如输出:9,输出为16
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1; //  n = n | (n >>> 1);
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
  1. 树化条件

    ①哈希桶中的元素数量>=8

    ②哈希表大小>=64

  2. 取消树化条件

    哈希桶中的元素数量<=6

相关推荐
CSharp精选营4 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假7 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠8 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦15 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾16 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q16 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记16 天前
单项不带头不循环链表
数据结构·链表