HashMap源码分析(1.7版本)
HashMap
采用的数据结构 = 数组(主) + 单链表(副),该数据结构方式也称:拉链法
具体描述如下
HashMap数组
其核心为一个table[] (哈希数组),数组的下标为处理过的HashMap键的hash值,数组元素为一个键值对或者一个链表的头节点。数组的大小为HashMap的容量。
HashMap链表
- 每个链表=哈希表的桶(bucket)
- 链表的节点值=1个键值对
- 链表长度=桶的大小
•链表主要用于解决hash冲突:若不同key值计算出来的hash值相同(即都需存储到数组的同1个位置),由于之前该hash值的数组位置已存放好元素, 则将原先位置的元素移到单链表中,冲突hash值对应的键值对放入到数组元素(即发生冲突时,新元素插入到链表头仲:制元素总是添加到歌组中,旧元素移到单链表中)
该采用链表解决hash冲突的方法=链地址法
HashMap
的本质 = 1个存储Entry
类对象的数组 + 多个单链表Entry
对象本质 = 1个映射(键 - 值对),属性包括:键(key
)、值(value
) & 下1节点(next
) = 单链表的指针 = 也是一个Entry
对象,用于解决hash
冲突
/**
* Entry类实现了Map.Entry接口
* 即 实现了getKey()、getValue()、equals(Object o)和hashCode()等方法
**/
static class Entry<K,V> implements Map.Entry<K,V> {
final K key; // 键
V value; // 值
Entry<K,V> next; // 指向下一个节点 ,也是一个Entry对象,从而形成解决hash冲突的单链表
int hash; // hash值
/**
* 构造方法,创建一个Entry
* 参数:哈希值h,键值k,值v、下一个节点n
*/
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;
}
/**
* equals()
* 作用:判断2个Entry是否相等,必须key和value都相等,才返回true
*/
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
/**
* hashCode()
*/
public final int hashCode() {
return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
}
public final String toString() {
return getKey() + "=" + getValue();
}
/**
* 当向HashMap中添加元素时,即调用put(k,v)时,
* 对已经在HashMap中k位置进行v的覆盖时,会调用此方法
* 此处没做任何处理
*/
void recordAccess(HashMap<K,V> m) {
}
/**
* 当从HashMap中删除了一个Entry时,会调用该函数
* 此处没做任何处理
*/
void recordRemoval(HashMap<K,V> m) {
}
}
V get(Object key); // 获得指定键的值
V put(K key, V value); // 添加键值对
void putAll(Map<? extends K, ? extends V> m); // 将指定Map中的键值对 复制到 此Map中
V remove(Object key); // 删除该键值对
boolean containsKey(Object key); // 判断是否存在该键的键值对;是 则返回true
boolean containsValue(Object value); // 判断是否存在该值的键值对;是 则返回true
Set<K> keySet(); // 单独抽取key序列,将所有key生成一个Set
Collection<V> values(); // 单独value序列,将所有value生成一个Collection
void clear(); // 清除哈希表中的所有键值对
int size(); // 返回哈希表中所有 键值对的数量 = 数组中的键值对 + 链表中的键值对
boolean isEmpty(); // 判断HashMap是否为空;size == 0时 表示为 空
HashMap扩容机制