1. 变量

这些变量可能会在源码阅读中反复出现

  • capacity: 容量,桶的数量 也就是table长度
  • threshold:临界值,默认16(capacity*loadFactor)当size大于threshold的时候会进行resize
  • loadFactor:加载因子 默认 0.75 减少hash冲突
  • modCount:数据修改次数 Iterator初始化的时候(HashIterator构造函数)expectedModCount = modCount。在使用迭代器遍历的时候判断两个值是否一致,如果调用map的put或者remove则 modCount会变化,则会报异常,所以要用迭代器的remove方法。
  • size:当前元素个数 put 的时候增加(createEntry方法) remove的时候减少 (removeEntryForKey)

2.构造函数

使用规定的容量和加载因子来创建

public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " + loadFactor);// 上面主要是对初始化数据的校验this.loadFactor = loadFactor;threshold = initialCapacity;init(); // HashMap中此方法未实现,LinkedHashMap有相应的实现
}

使用已经存在的map对象来构建HashMap

public HashMap(Map<? extends K, ? extends V> m) {// 取16和 size/0.75 + 1 较大值,使用默认加载因子0.75this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);inflateTable(threshold);putAllForCreate(m);
}

填充table,如果table为空,初始化 table 为 x 且 x 为 2的n次数 >= threshold 之后resize 的时候 都是 table.length * 2 所以长度都是2的倍数

private void inflateTable(int toSize) {// roundUpToPowerOf2 中确保 toSize >= 0 ,返回一个最接近 toSize 的次方数int capacity = roundUpToPowerOf2(toSize);// threshold 最大不能超过 (1 << 30) + 1threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);table = new Entry[capacity];initHashSeedAsNeeded(capacity);
}

3.put源码

首先来张图整体感受下流程

put方法

public V put(K key, V value) {if (table == EMPTY_TABLE) {inflateTable(threshold);}// 如果 key 为空 则特殊处理(因为下面调用key对象的hash()方法,null无法调用hash方法,会空指针)if (key == null)return putForNullKey(value);// 获取 key 的 hash 并获取 hash 在 table.length 的第 i 个int hash = hash(key);int i = indexFor(hash, table.length);// 获取 tabel[i] 的 entry, 如果为空或者链表中不存在对应的key,则调用addEntry方法// 如果匹配到,则用新值替换旧值,返回 oldValuefor (Entry<K,V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(hash, key, value, i);return null;
}

putForNullKey

// 循环table 查看是否有 key 为null的 entry 有则话用新值替换旧值,并直接return
// 如果没有key为null 则调用 addEntry 方法 并放入table的第 0 位 (null 的 hash 都认为是 0 )
private V putForNullKey(V value) {for (Entry<K,V> e = table[0]; e != null; e = e.next) {if (e.key == null) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(0, null, value, 0);return null;
}

addEntry

void addEntry(int hash, K key, V value, int bucketIndex) {// 如果 size 大于等于 threshold 且 table[i] 不为空(说明要在table上面添加新的元素需要调用resize方法)if ((size >= threshold) && (null != table[bucketIndex])) {resize(2 * table.length);  // table扩容hash = (null != key) ? hash(key) : 0; // 对于key重新获取 hashbucketIndex = indexFor(hash, table.length); // 重新获取在table上的位置}// 新建节点createEntry(hash, key, value, bucketIndex);
}

createEntry

void createEntry(int hash, K key, V value, int bucketIndex) {Entry<K,V> e = table[bucketIndex];table[bucketIndex] = new Entry<>(hash, key, value, e); // 将新放入的值至于链表的头部size++; // 大小增加
}

4.扩容

查看resize方法

void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;// 如果table长度已经为最大值则不处理if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}Entry[] newTable = new Entry[newCapacity];transfer(newTable, initHashSeedAsNeeded(newCapacity)); // 将table = newTable;threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}

transfer 用新数组的length 重新获取每个key 的 index 值 并将每个放入新的table

void transfer(Entry[] newTable, boolean rehash) {int newCapacity = newTable.length;for (Entry<K,V> e : table) {while(null != e) {Entry<K,V> next = e.next;if (rehash) { // 如果需要rehash 则重新用新的hashseed来获取hashe.hash = null == e.key ? 0 : hash(e.key);}int i = indexFor(e.hash, newCapacity);e.next = newTable[i];newTable[i] = e;e = next;}}
}

图解HashMap源码相关推荐

  1. HashMap 源码详细分析(JDK1.8)

    1. 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值 ...

  2. hashmap remove 没释放内存_java从零开始手写 redis(13)HashMap 源码原理详解

    为什么学习 HashMap 源码? 作为一名 java 开发,基本上最常用的数据结构就是 HashMap 和 List,jdk 的 HashMap 设计还是非常值得深入学习的. 无论是在面试还是工作中 ...

  3. 在参考了众多博客之后,我写出了多达三万字的HashMap源码分析,比我本科毕业论文都要精彩

    HashMap源码分析 以下代码都是基于java8的版本 HashMap简介 源码: public class HashMap<K,V> extends AbstractMap<K, ...

  4. HashMap 源码详细分析(JDK1.8) 1

    1.概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值, ...

  5. JDK7中HashMap源码分析

    文章目录 JDK7中的HashMap 一.JDK7中HashMap源码中重要的参数 二.JDK7中HashMap的构造方法 三.JDK7中创建一个HashMap的步骤 四.JDK7中HashMap的p ...

  6. JDK8 HashMap源码解析

    1.概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值, ...

  7. HashMap源码实现分析

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 一.前言 HashMap 顾名思义,就是用hash表的原理 ...

  8. Java源码详解二:HashMap源码分析--openjdk java 11源码

    文章目录 HashMap.java介绍 1.HashMap的get和put操作平均时间复杂度和最坏时间复杂度 2.为什么链表长度超过8才转换为红黑树 3.红黑树中的节点如何排序 本系列是Java详解, ...

  9. JDK 1.6 HashMap 源码分析

    前言 ​ 前段时间研究了一下JDK 1.6 的 HashMap 源码,把部份重要的方法分析一下,当然HashMap中还有一些值得研究得就交给读者了,如有不正确之处还望留言指正. 准备 ​ 需要熟悉数组 ...

最新文章

  1. Eigen矩阵运算的混淆问题
  2. VirtualBox 下USB 设备加载的步骤及无法加载的解决办法
  3. Javascript 数组
  4. 操蛋的linux改mysql密码(1054和1819错误)
  5. 【数据结构与算法】之深入解析“有效的括号”的求解思路与算法示例
  6. 我和阿里巴巴的孽缘(三)
  7. 如何验证 MySQL 的 InnoDB 在可重复读下依然会有幻影行问题及其原因
  8. java实现下载时进度条提示
  9. C# async await
  10. memset 函数使用
  11. VS2005 My.Computer.Registry 对象 操作注册表 简单示例
  12. java常量池存放什么_java常量池存放在哪里
  13. java替换图片文字_Java 替换PPT文档中的文本和图片
  14. html css动漫素材,66种特效的CSS3动画库animate.css
  15. wsl 设置阿里云源
  16. 澳洲学计算机难毕业吗,澳洲新南威尔士大学计算机专业好吗
  17. 量子计算机核心技术突破,量子芯片研发有突破 我们距离量子计算机不远了
  18. 江苏农村商业银行计算机类笔试考什么时候,2020江苏农商行春季校园招聘笔试考什么?...
  19. Python进行网页自动打卡系统
  20. 一篇很值得看的伤感日志:因为你不喜欢我,所以你不明白

热门文章

  1. 物联网专科专业必修课程_物联网工程专业主要课程大纲
  2. 计算机教室冷量负荷,空调设计时,楼层或者个别房间的空调冷负荷是怎样确定的...
  3. Java ibatis批量insert,ibatis批量insert是什么写法?要怎么编写?
  4. ubuntu18.04 安装HP打印机
  5. Vue3中使用svg文件图标(TS)
  6. PYthon调整音乐音量,生成空白音乐
  7. java 放大mp3音量_MP3的歌曲声音如何放大
  8. FrontPage基础教程 表单的设计
  9. 用友网络并购秉钧网络 加速布局企业互联网服务
  10. 【php】基于Xajax的在线聊天室、直播间