/**
 * HashMap主要方法解析,jdk1.7版本的HashMap
 * HashMap数据是通过数组和链表结合的方式(链表散列)存储。
 * 在put时候根据key值得到hash值(地址)即数组下标,之后如果得到相同下标则放在链表前面,之前的数据在链表尾部。                   
 * 之前的数据在链表尾部。  
 *  在查找数据时候根据hashcode获取数组下标,在链表中使用equals根据key查找value.

 * 一、构造
 * 4个构造相对之前的jdk版本功能基本不变,但是代码封装更完善。
 * 构造前一个参数是容量,相当于数组大小,后一个是负载因子
 */
public HashMap(int initialCapacity, float loadFactor) {
        //当初始容量<0,抛出异常非法的参数容量
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        //初始容量不能大于最大容量值,最大容量值为MAXIMUM_CAPACITY = 1 << 30;   
        //左移一位相当于乘以2,所以左移30位相当于2^30.
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        //负载因子不为空并且<=0
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        //保存参数并且初始化数组
        this.loadFactor = loadFactor;
        threshold = initialCapacity;
        //此初始化将插入数据,主要使用Entry
        init();
    }
//无参构造默认容量是16,负载因子0.75
public HashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }
//指定容量参数,默认负载因子0.75
public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
/构造与指定map相同映射的新HashMap 
public HashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        //如果容量不够,扩大table数组
        inflateTable(threshold);
        //将map中的元素添加到HashMap中
        putAllForCreate(m);
    }
 
/**
 * 二、创建数据链
 * 静态内部类,包含键值,节点next和hash值,由于他的存在,才会让table数组项以链表方式存在
 */
static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;
 
        //添加新条目
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }
 
        public final K getKey() {
            return key;
        }
 
        public final V getValue() {
            return value;
        }
 
        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
        。
        。
        。
        。
        。
 /**
  *  三、存
  *  实现快速存取
  *  添加数据
  */
public V put(K key, V value) {
        //如果数组为空,添加数组容量
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        //如果key为空,保存null在table的第一个位置,所以HashMap可以为null
        if (key == null)
            return putForNullKey(value);
        //计算hash值
        int hash = hash(key);
        //计算key的hash值在table中的位置(索引)
        int i = indexFor(hash, table.length);
        //从i迭代e,找到key保存的位置
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            //判断该链上是否有hash(key)值相同的情况,若存在,则将其value值覆盖,保留新value
            //新值等于旧值,返回旧值
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        //修改次数加一
        modCount++;
        //将key,value值添加在i处
        addEntry(hash, key, value, i);
        return null;
    }
//都是添加Entry,这个是HashMap实际容量超过容器容量,下面的方法是没超过的情况
void addEntry(int hash, K key, V value, int bucketIndex) {
        //当HashMap大小不小于临界值(容量*负载因子)大小,并且数组bucketIndex位置不为null,改变HashMap大小,记录索引
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
        //否则调用createEntry方法
        createEntry(hash, key, value, bucketIndex);
    }
 
//HashMap实际容量未超过默认容量或者初始化容量
void createEntry(int hash, K key, V value, int bucketIndex) {
        //保存bucketIndex的所在位置到e中
        Entry<K,V> e = table[bucketIndex];
        //设置bucketIndex位置元素为新Entry,并且设置e为新Entry下一个节点
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }
/**
  *  四、取
  *  实现快速存取
  *  获取数据
  */
public V get(Object key) {
        //若key为null,调用getForNullKey取出value
        if (key == null)
            return getForNullKey();
        //根据key值算出hash值并取出table对应索引处的值
        Entry<K,V> entry = getEntry(key);
 
        return null == entry ? null : entry.getValue();
    }
 
final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }
        //计算hash值
        int hash = (key == null) ? 0 : hash(key);
        //根据hash值取出table对应索引处的值
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
}

【学习笔记-集合】HashMap 源码浅析相关推荐

  1. K8s基础知识学习笔记及部分源码剖析

    K8s基础知识学习笔记及部分源码剖析 在学习b站黑马k8s视频资料的基础上,查阅了配套基础知识笔记和源码剖析,仅作个人学习和回顾使用. 参考资料: 概念 | Kubernetes 四层.七层负载均衡的 ...

  2. JUC.Condition学习笔记[附详细源码解析]

    JUC.Condition学习笔记[附详细源码解析] 目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Conditi ...

  3. HashMap源码浅析

    HashMap源码主要一些属性 //默认的初始化容量(2的n次方) static final int default_inital_capacity = 16; //最大指定容量为2的30次方 sta ...

  4. 集合—HashMap源码

    4-1 HashMap源码(2021-11-9) 1 Map接口和常用方法(jdk1.8) 用于保存具有映射关系数据key-value双列元素. Map中的key和value可以是任何类型元素,会封装 ...

  5. Netty学习笔记 - 1 (带源码分析部分)

    2021年12月 北京 xxd 一.Netty是什么 Netty 是由 JBOSS 提供的一个 Java 开源框架,现为 Github 上的独立项目. Netty 是一个异步的.基于事件驱动的网络应用 ...

  6. The Things Network LoRaWAN Stack V3 学习笔记 1.2 源码编译

    前言 源码编译是重头戏,这节笔记记录如何使用 make 命令编译相关部件.由于部分包在墙外,带来了一点麻烦,还分享一个 replace 方式来翻墙的办法. 小能手这段时间在学习 The Things ...

  7. Vuex 4源码学习笔记 - 通过Vuex源码学习E2E测试(十一)

    在上一篇笔记中:Vuex 4源码学习笔记 - 做好changelog更新日志很重要(十) 我们学到了通过conventional-changelog来生成项目的Changelog更新日志,通过更新日志 ...

  8. 【从线性回归到 卷积神经网络CNN 循环神经网络RNN Pytorch 学习笔记 目录整合 源码解读 B站刘二大人 绪论(0/10)】

    深度学习 Pytorch 学习笔记 目录整合 数学推导与源码详解 B站刘二大人 目录传送门: 线性模型 Linear-Model 数学原理分析以及源码详解 深度学习 Pytorch笔记 B站刘二大人( ...

  9. The Things Network LoRaWAN Stack V3 学习笔记 1.2 源码编译 - 190821

    文章目录 前言 1 依赖包替换 2 编译准备 3 编译 3.1 cli 编译 3.2 stack 编译 3.3 前端编译 END 前言 源码编译是重头戏,这节笔记记录如何使用 make 命令编译相关部 ...

  10. jMetal学习笔记(二)-NSGAii源码解读

    前言 上篇笔记根据使用手册介绍了jMetal的架构,但是由于使用手册撰写时间太早(最近更新时间是08年),现在jmetal框架更新了,所以很多都已经不适用,这篇笔记会穿插讲解jmetal架构知识. 其 ...

最新文章

  1. 【转载】mysql常用函数汇总
  2. 获取ip地理位置的 api接口 简介
  3. substring和charindex的使用注意
  4. 基于Redis的分布式锁到底安全吗(上)?
  5. 神策数据丨九大行业数字化经营指南集锦,值 100% 收藏
  6. Android-NDK-hello-jniCallback
  7. mysql 开发 生产_在没有表锁定的情况下在巨大的MySQL生产表...
  8. 管理全局包、缓存和临时文件夹
  9. “洗净净”、“洗香香”、“洗爽爽” 京东又申请了这些商标
  10. CentOS7 设置防火墙端口
  11. Manjaro下安装VirtualBox
  12. 【温故而知新-Javascript】使用canvas元素(第一部分)
  13. leetcode28 Implement strStr() 在字符串中寻找目标字符串
  14. linux deepin 15.9双系统,windows10安装双系统Deepin15.9遇到的坑
  15. 100个最常用的PHP函数(建议收藏)
  16. Windows10系统迁移-同一PC硬盘之间
  17. 数据库原理与应用(五)专门的关系运算
  18. 大一C语言大作业_网吧收费管理系统
  19. 第1关:启动 MongoDB
  20. 十年项目经理总结的项目质量管理十要点

热门文章

  1. 珍惜那些爱你的人,不要令他们失望,加油吧,我们。
  2. Silverlight控件-Slider
  3. MATLAB中的wavedec、wrcoef函数简析
  4. Linux常用命令集锦
  5. 深入浅出CUDA编程
  6. caffe教程翻译:Alex’s CIFAR-10 tutorial, Caffe style
  7. 通过History Trends Unlimited通过统计笔记本Chrome浏览器Top10网页历史访问量(截止至2021.11.23)
  8. 编程打怪升级之路2018-06-01
  9. 动态服务器值 回放报错 没有关联到_性能测试每天两个知识点-web性能脚本回放不成功的解决方法...
  10. VC++下的OpenGL编程