Java集合深入学习 - HashMap源码解析-1基础(基于jdk1.8)
Java集合深入学习 - HashMap源码解析-2查找数据(基于jdk1.8)
Java集合深入学习 - HashMap源码解析-3添加与扩容(基于jdk1.8)
Java集合深入学习 - HashMap源码解析-4删改与遍历(基于jdk1.8)
1.类的定义
话不多说,还是直接上代码
/**
* AbstractMap 抽象Map
* Map Map 接口
* Cloneable 克隆
* Serializable 序列化
*/
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {}
/**
* 抽象Map类 实现了Map接口的部分方法
*/
public abstract class AbstractMap<K,V> implements Map<K,V> {}
/**
* Map接口
*/
public interface Map<K,V> {}
2.属性,节点与构造方法
2.1 HashMap的各个属性解释
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
private static final long serialVersionUID = 362498820763181265L;
/**
* 默认初始容量
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 最大容量
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认加载因子
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 桶的树化阈值:即 链表转成红黑树的阈值,在存储数据时,当链表长度 > 该值时,则将链表转换成红黑树
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 桶的链表还原阈值:即 红黑树转为链表的阈值,当在扩容(resize())时(此时HashMap的数据存储位置会重新计算),在重新计算存储位置后,当原有的红黑树内数量 < 6时,则将 红黑树转换成链表
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* 最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即 将链表 转换成红黑树)
* 否则,若桶内元素太多时,则直接扩容,而不是树形化
* 为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD
*/
static final int MIN_TREEIFY_CAPACITY = 64;
/**
* 节点数组
*/
transient Node<K,V>[] table;
/**
* HashMap将数据转换成set的另一种存储形式,这个变量主要用于迭代功能。
*/
transient Set<Map.Entry<K,V>> entrySet;
/**
* HashMap中实际存在的Node数量,注意这个数量不等于table的长度,因为在table的每个节点上是一个链表(或RBT)结构,可能不止有一个Node元素存在。
*/
transient int size;
/**
* 操作次数
*/
transient int modCount;
/**
* HashMap的扩容阈值,在HashMap中存储的Node键值对超过这个数量时,自动扩容容量为原来的二倍。
*/
int threshold;
/**
* HashMap的负载因子,可计算出当前table长度下的扩容阈值:threshold = loadFactor * table.length。
*/
final float loadFactor;
}
2.2 HashMap的节点定义
/**
* HashMap节点定义 实现Map中的Entry
* --链表节点
*/
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; //hash值
final K key; //key
V value; //value值
Node<K,V> next; //下一个节点
}
/**
* Map接口中的节点接口定义
*/
interface Entry<K,V> {}
/**
* HashMap的节点定义 继承LinkedHashMap中的Entry
* --红黑树的节点
*/
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; //父节点
TreeNode<K,V> left; //左子节点
TreeNode<K,V> right; //右子节点
TreeNode<K,V> prev; //上一个节点(与父类中的next一起使用)
boolean red; //记录树的颜色
}
/**
* LinkedHashMap定义的Entry 继承自HashMap中Node节点类
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
/**
* before,before分别指向前一个节点与后一个节点
*/
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
2.3 HashMap的构造方法
/**
* 初始化方法传入参数为扩容阈值和负载因子
*/
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;
this.threshold = tableSizeFor(initialCapacity);
}
/**
* 初始化方法传入参数为扩容阈值
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);//负载因子默认为DEFAULT_LOAD_FACTOR
}
/**
* 空参构造函数 负载因子默认为DEFAULT_LOAD_FACTOR
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
/**
* 传入Map进行构造 负载因子默认为DEFAULT_LOAD_FACTOR
*/
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
/**
* 根据Map初始化一个HashMap
*/
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size(); //获取map大小
if (s > 0) { //传入map非空
if (table == null) { // 数组为空
float ft = ((float)s / loadFactor) + 1.0F; //获取当前table容量
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY); //最大值校验
if (t > threshold) //若得到值大于默认值
threshold = tableSizeFor(t); //重新计算HashMap的扩容阈值
}
else if (s > threshold) //数组非空 判断当前是否需要扩容
resize(); //扩容(之后再说)
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { //遍历节点
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict); //将值存入HashMap中(之后再说)
}
}
}
/**
* 对cap进行转换 转换成大于等于cap的最小的2的整数次幂的数
*/
static final int tableSizeFor(int cap) {
int n = cap - 1; //当前值-1避免传入值为2的整数次幂时计算值出错
//当前值二进制为 ***1***
n |= n >>> 1; //处理后 ***11***
n |= n >>> 2; //处理后***1111**
n |= n >>> 4; //同上
n |= n >>> 8; //同上
n |= n >>> 16; //处理n值为 大于等于cap的最小的2的整数次幂的数 - 1
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
本文连接,转载请标注https://blog.csdn.net/luo_mu_hpu/article/details/106191080