HashMap分析
第1部分 HashMap介绍
HashMap简介
HashMap实现了Map接口,提供关于K,V和Entry的操作。
HashMap实现了Cloneable接口,提供了clone方法。
HashMap实现了Serializable接口,提供了序列化和反序列化方法。
HashMap构造函数
修饰语和返回类型 | 方法 | 描述 |
---|---|---|
public | HashMap(int initialCapacity, float loadFactor) | 传入初始容量和加载因子 |
public | HashMap(int initialCapacity) | 传入初始容量 |
public | HashMap() | 默认构造方法 |
public | HashMap(Map<? extends K, ? extends V> m) | 根据m构造 |
HashMap常用API
修饰语和返回类型 | 方法 | 描述 |
---|---|---|
int | size() | 元素数量 |
boolean | isEmpty() | 为空 |
V | get(Object key) | 根据key获取value |
boolean | containsKey(Object key) | 包含key对应元素 |
V | put(K key, V value) | 添加元素 |
V | remove(Object key) | 移除key对应的元素 |
void | clear() | 清空 |
boolean | containsValue(Object value) | 包含value |
Set<K> | keySet() | 获取key集合 |
Collection<V> | values() | 获取value集合 |
Set<Map.Entry<K,V>> | entrySet() | 获取entry集合 |
第2部分 HashMap数据结构
HashMap的继承关系
java.lang.Object
↳ java.util.AbstractMap<K,V>
↳
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {}
HashMap的关系图
图1 HashMap的关系图
其中table是一个桶数组,其每个桶可以是一条单向链表,也可以是一个即是双向链表,又是红黑树的复合结构,下文简称红黑树。
注意是每个桶都可以是这两种结构,而不是整个HashMap构成一个红黑树。
第3部分 HashMap源码解析(基于JDK-8u201)
内部类Node
Node是构成HashMap的基本结点,是组成每个桶中链表的基本元素,HashMap采用开链法解决冲突时,将冲突节点依次存在对应桶后的链表尾部。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;//哈希值
final K key;
V value;
Node<K,V> next;//指向链表中下一个节点
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() {
return key; }
public final V getValue() {
return value; }
public final String toString() {
return key + "=" + value; }
//哈希值为key和value的哈希值异或后的结果
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
//地址相同
if (o == this)
return true;
//否则,要求是Map.Entry类型,并且K,V分别等价
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
Node结点的方法比较简单,重点关注其结构,也就是链表
图2 Node的链表结构
三个内部集合类
KeySet ,Values ,EntrySet这三个主要都是提供内部元素的迭代,因此放一起看。
final class KeySet extends AbstractSet<K> {
public final int size() {
return size; }
public final void clear() {
HashMap.this.clear(); }
//获取KeyIterator迭代器,这个迭代器在后面说,
public final Iterator<K> iterator() {
return new KeyIterator(); }
public final boolean contains(Object o) {
return containsKey(o);}
//调用HashMap的removeNode方法
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
//获取可分割迭代器,JDK8新增
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
//Collection接口提供的方法,JDK8新增
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
//HashMap中有元素,并且将table的引用传给tab遍历
if (size > 0 && (tab = table) != null) {
int mc = modCount;
//遍历每个桶
for (int i = 0; i < tab.length; ++i) {
//遍历桶中的链表,调用消费器方法
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
//fast-fail机制,确保迭代过程中没有被修改
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
final class Values extends AbstractCollection<V> {
public final int size() {
return size; }
public final void clear() {
HashMap.this.clear(); }
public final Iterator<V> iterator() {
return new ValueIterator(); }
public final boolean contains(Object o) {
return containsValue(o); }
public final Spliterator<V> spliterator() {
return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() {
return size; }
public final void clear() {
HashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
//在hash(key)的桶中,找到key对应的结点,这样只需要遍历一条链表
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator<Map.Entry<K,V>> spliterator() {
return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
上面三个集合特别像,主要都是提供两种迭代器和forEach方法,后面将介绍这两种迭代器。
内部类Iterator
/*
提供后面三种Iterator迭代的抽象,实现大部分方法
注意其内部并没有提供抽象方法,也没有实现Iterator接口,
但是实现了除next外的所有方法,nextNode返回的是Node(也就是Entry)结点
*/
abstract class HashIterator {
Node<K,V> next; //要迭代的下一结点,next时使用
Node<K,V> current;//当前节点,删除时使用
int expectedModCount;// fast-fail机制
int index;//桶的索引
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;//将HashMap对象的数据传进来
current = next = null;
index = 0;
//如果有元素
if (t != null && size > 0) {
// advance to first entry
//找到第一个链表非空的桶,并将next指向该链表的头
do {
} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
//获取下一个元素
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
/*
如果e也就是原先的next非空,直接把这个"next"返回,并且next后移
否则,查找下一个链表非空的桶,并将next指向该链表的头
*/
if ((next = (current = e).next) == null && (t = table) != null) {
do {
} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
//移除current元素
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
//根据current的key调用HashMap的removeNode方法
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
//KeyIterator,next方法具体方法的key,其他Iterator接口中的方法在其父类中实现
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() {
return nextNode().key; }
}
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() {
return nextNode().value; }
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() {
return nextNode(); }
}
从上面的设计中,可以看出模板设计模式的影子,抽象父类将大部分方法实现,子类只需要提供简单的具体实现。虽然这不是模板设计模式,但是在平时写代码的过程中,也要尽量将重复的部分进行提取,避免重复造轮子。
内部类Spliterator
static class HashMapSpliterator<K,V> {
final HashMap<K,V> map;
Node<K,V> current; //当前节点
int index; //当前索引,在advance/split中会修改
int fence; //最后一个索引,也就是桶数组的长度
int est; //评估容量
int expectedModCount;
HashMapSpliterator(HashMap<K,V> m, int origin,
int fence, int est,
int expectedModCount) {
this.map = m;
this.index = origin;
this.fence = fence;
this.est = est;
this.expectedModCount = expectedModCount;
}
//初始化最后一个索引
final int getFence() {
// initialize fence and size on first use
int hi;
/*第一次使用时fence<0才会调用,例如
KeySpliterator<>(HashMap.this, 0, -1, 0, 0),
传入的fence为-1,需要初始化
*/
if ((hi = fence) < 0) {
HashMap<K,V> m = map;
est = m.size;
expectedModCount = m.modCount;
Node<K,V>[] tab = m.table;
//获取长度
hi = fence = (tab == null) ? 0 : tab.length;
}
return hi;
}
//获取预估容量,也就是HashMap的Size
public final long estimateSize() {
getFence(); // force init
return (long) est;
}
}
static final class KeySpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<K> {
KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
//尝试切分
public KeySpliterator<K,V> trySplit() {
//将桶数组范围切半
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
//预估容量也切半,注意,这个数据是不准确的,只是个大概
new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
//对[index,fence]
public void forEachRemaining(Consumer<? super K> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table;
//初始化
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
//i的范围[index,fence),index改为fence,也就是结尾
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node<K,V> p = current;
current = null;
do {
//p == null,一般是到了链表的表尾
if (p == null)
p = tab[i++];//下个桶的链表头
else {
action.accept(p.key);
p = p.next;//指向链表的下一个结点
}
} while (p != null || i < hi);
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
}
//消费单个元素
public boolean tryAdvance(Consumer<? super K> action) {
int hi;
if (action == null)
throw new NullPointerException();
Node<K,V>[] tab = map.table;
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];//到链表尾,桶索引+1
else {
K k = current.key;
//后移
current = current.next;
action.accept(k);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
return false;
}
//特征码
public int characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
//后面两个可分割迭代器与key的差不多,就不分析了
static final class ValueSpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<V> {
ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public ValueSpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
public void forEachRemaining(Consumer<? super V> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table;
if ((hi = fence) < 0