HashMap源码学习记录
2020-05-11 04:08
274 查看
HashMap源码学习记录
2020.4.13 每天进步一点点
HashMap是什么?
HashMap是基于哈希表的Map接口实现,是以key-value存储的形式存在,即主要用来存放键值对HashMap不是同步的,这意味着他不是线程安全的。他的key、value都可以为null。此外HashMap中的映射不是有序的。
HashMap的数据结构
JDK1.8之前HashMap由数组=链表组成,数组是HashMap的主体。链表则是要未来解决哈希冲突而存在的。哈希冲突是指:两个对象调用的hashCode方法计算的 哈希码值一直导致计算的数组索引相同而存在的。
JDK1.8之后当链表长度大于阈值(或者红黑树边界,默认值为8)且当期数组长度大于64时,此时索引位置上所有数据改为使用红黑数存储。
HashMap 源码中包含了以下几个属性:
// HashMap 初始化长度
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
// HashMap 最大长度
static final int MAXIMUM_CAPACITY = 1 << 30; // 1073741824
// 默认的加载因子 (扩容因子)
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 当链表长度大于此值且容量大于 64 时
static final int TREEIFY_THRESHOLD = 8;
// 转换链表的临界值,当元素小于此值时,会将红黑树结构转换成链表结构
static final int UNTREEIFY_THRESHOLD = 6;
// 最小树容量
static final int MIN_TREEIFY_CAPACITY =
HashMap 新增方法 put
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * Implements Map.put and related methods * * @param hash hash for key 通过hashCode()方法 计算的hash值 * @param key the key 键 * @param value the value to put 值 * @param onlyIfAbsent if true, don't change existing value 表示不要更改现有值 * @param evict if false, the table is in creation mode.表示table处于创建模式 * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab;//创建一个接收数组 Node<K,V> p;//创建一个键值对 int n, i; if ((tab = table) == null || (n = tab.length) == 0) //这个判断作用是判断数组是否存在,再一次存入数据对数组进行初始化。 //table是HashMap初始化定义的数组未赋值所以table=null // n=tab.length表示数组的长度 n = (tab = resize()).length; // 运用到resize()方法来创建数组,并且把数组的长度传给定义好的n // resize()这个方法也可以用来扩容 if ((p = tab[i = (n - 1) & hash]) == null) //如果计算的数组索引位置上不存在数据。直接创建节点插入 (n - 1) & hash计算数组的索引 //赋值给定义好的i. 。如果这个索引p=tab[i]位置上的值为null.则执行下一条语句 tab[i] = newNode(hash, key, value, null); //tab[i] 为null,直接将新的key-value插入到计算的索引i位置 else {//如果计算的位置上已有数据 Node<K,V> e; K k; if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k)))) // 判断p.hash==tab[i].hash的hash值与传入的hash进行比较, //p.key==tab[i].key 是否等于参数key 或者String.equals相等 // ,则是覆盖原来的值,覆盖的方法在下面的 if (e != null) 判断中执行。 e = p; //给e赋值p让其不为null,执行下面的 if (e != null) 判断语句执行覆盖操作。 else if (p instanceof TreeNode) //判断是不是红黑树 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //添加到红黑树 else { //else是判断链表的情况下key没有相同的情况在尾部插入键值对 for (int binCount = 0; ; ++binCount) {//循环方法添加数据 if ((e = p.next) == null) { //尾插法判断 p.next = newNode(hash, key, value, null); //找到节点链表中next空的节点,创建新的节点插入 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 链表长度大于 8(TREEIFY_THRESHOLD (8)),转换成红黑树 treeifyBin(tab, hash); break; } //在链表的情况下key有相同的。情况下替换操作 if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k)))) //如果节点链表中有发现已有相同key,如果哈希和K的equals都相等,跳出循环。 //执行下面的 if (e != null)替换tab[i=(n-1)&hash].next的值 break; p = e; } } if (e != null) { // existing mapping for key 覆盖原值的方法 V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount;//用作修改计数 if (++size > threshold) //当前大小大于领界大小,扩容 resize(); afterNodeInsertion(evict); return null; }qintaipeng 原创文章 8获赞 0访问量 199 关注 私信
相关文章推荐
- Java HashMap源码学习记录(一)
- JDK源码学习之HashMap (一) : 底层存储结构分析
- JDK源码学习之:HashSet和HashMap
- 【jdk源码3】HashMap源码学习
- java.util.HashMap源码学习(一)
- Swoole源码学习记录(十四)——Server模块详解(下)
- lucene全文检索学习记录,附带源码——三种实现,超全超细致
- 集合源码学习(十):HashTable(Java8)与HashMap比较
- JDK源码学习(6)-ConcurrentHashMap代码学习
- TreeMap和HashMap源码学习
- 基于jdk1.8的HashMap源码学习笔记
- 哈希算法-----JAVA 源码中实现的HashMap学习总结
- Java记录 -71- HashMap源码剖析
- JDK1.8源码学习之ConcurrentHashMap.java
- WPF 学习记录——源码实例
- Mysql源码编译安装Mysql5.7版本(记录下学习的过程)
- select 源码学习记录
- Swoole源码学习记录(二)——三种MemoryPool(上)
- 集合学习--HashMap 源码初探
- Swoole源码学习记录(五)——锁和信号(二)