package java.util;
import java.io.*;
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
/**
* 默认的初始容量,必须是2的幂
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* MUST be a power of two <= 1<<30.
* 最大容量,如果构造方法没有设置参数将指定一个较高值
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认装载因子。
* 默认的entry数组的长度为16。装载因子的意义在于使得entry数组有冗余,
* 默认即允许25%的冗余,当HashMap的数据的个数超过12(16*0.75)时
* 即会对entry数组进行第一次扩容,后面的再次扩容依次类推。
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 存储实体的数组,可调整。数据长度总是2的幂
* transient 序列化时忽略该字段。数组存放的是实体的引用,序列化时必须遍历该字段逐个实体序列化。
*/
transient Entry[] table;
/**
* 键值对的数目
* transient 序列化时忽略该字段。反序列化的时候读取出每对key、value值,再存入HashMap的数组中
*/
transient int size;
/**
* 下一个容量调整值(扩容临界值)
*/
int threshold;
/**
* 装载因子
* @serial
*/
final float loadFactor;
/**
* map结构被改变的次数
* 结构上的修改是指更改在HashMap中映射的数量或以其他方式修改它的内部结构(例如,刷新)
* 该字段在HashMap使用迭代器遍历的时候使用
*/
transient volatile int modCount;
/**
* 根据初始容量和加载因子创建一个空的HashMap
* (初始容量小于0或装载因子小于等于0将报异常)
*/
public HashMap(int initialCapacity, float loadFactor) {
// 初始容量小于0,抛出非法参数异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
// 初始容量大于最大容量,调整初始容量
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
// 加载因子小于等于0或者非浮点数,抛出非法参数异常
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
// 设置capacity为大于initialCapacity且是2的幂的最小值
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
//设置加载因子
this.loadFactor = loadFactor;
//设置扩容临界值
threshold = (int)(capacity * loadFactor);
//创建数组
table = new Entry[capacity];
//初始化
init();
}
/**
* 根据指定容量创建一个空的HashMap
*/
public HashMap(int initialCapacity) {
// 调用上面的构造方法,容量为指定的容量,装载因子是默认值
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* 根据默认初始化容量和默认加载因子(0.75)创建HashMap
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
/**
* 通过传入的map创建一个HashMap,容量为默认容量(16)和(map.zise()/DEFAULT_LOAD_FACTORY)+1
* 的较大者,装载因子为默认值
*/
public HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
putAllForCreate(m);
}
// internal utilities
/**
* 初始化方法(钩子方法)
* 所有的构造方法和伪构造方法(clone,readObject)将在HashMap初始化完成之后,元素插入之前调用该方法
*/
void init() {
}
/**
* 适用补充hash函数,防止质量较差的hash函数。
* 该方法主要作用是防止质量较差的哈希函数带来过多的冲突(碰撞)问题。
* Java中int值占4个字节,即32位。根据这32位值进行移位、异或运算得到一个值。
*/
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
/**
* 返回Hash code h的值在存储数组中的索引
* 为啥和length-1进行与运算,因为这样可以保证结果的最大值是length-1,不会产生数组越界问题。
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
/**
* 键存储值对的数量
*/
public int size() {
return size;
}
/**
* 判断map是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 根据key查询value
*
* @see #put(Object, Object)
*/
public V get(Object key) {
//key为空
if (key == null)
return getForNullKey();
//计算key哈希
int hash = hash(key.hashCode());
//遍历链表
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.equals(k)))
return e.value;
}
return null;
}
/**
* 查询key为null时的值
*/
private V getForNullKey() {
//遍历索引为零的链表,key为null时映射的索引位置为0
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
/**
* 是否包含key
*/
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
/**
* 根据key获取对应的值,没有则返回空
*/
final Entry<K,V> getEntry(Object key) {
//计算哈希值
int hash = (key == null) ? 0 : hash(key.hashCode());
//遍历链表,查询对应的值
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;
}
/**
* 将指定的值映射指定的键。如果指定的键已存在映射关系,则旧值会被替换。
*/
public V put(K key, V value) {
//如果key为空,则调用putForNullKey方法
if (key == null)
return putForNullKey(value);
//调用补充hash方法(防止低质量hash方法造成冲突过多问题)
int hash = hash(key.hashCode());
//获取hash code对应的存储数组索引
int i = indexFor(hash, table.length);
//遍历目标存储数组单元下的链表
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//如果已存在键值对值的hash等于将要插入兼职对值的hash,并且已存在键值对键等于将要插入键值对键
//(内存地址相等或者equals)
//即同键值覆盖
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
//返回旧值
return oldValue;
}
}
//修改记录Map改变次数的值
modCount++;
//添加键值对
addEntry(hash, key, value, i);
return null;
}
/**
* 空键插入(私有方法)
*/
private V putForNullKey(V value) {
//先遍历数组,如果存在key为空的,先替换值并返回旧值
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//更新修改次数
modCount++;
//添加值
addEntry(0, null, value, 0);
return null;
}
/**
* 该方法被构造函数和伪构造函数(clone,readObject)用来替代put方法。
* 该方法不扩展数组,不检查map修改次数,方法体调用createEntry方法而非addEntry
*
*/
private void putForCreate(K key, V value) {
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
/**
* Look for preexisting entry for key. This will never happen for
* clone or deserialize. It will only happen for construction if the
* input Map is a sorted map whose ordering is inconsistent w/ equals.
*
* 遍历已存在的键,如果和当前key相等,则值替换后返回
*/
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
e.value = value;
return;
}
}
// 没有则创建
createEntry(hash, key, value, i);
}
/**
* 将指定map中数据插入到当前map中
*/
private void putAllForCreate(Map<? extends K, ? extends V> m) {
for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<? extends K, ? extends V> e = i.next();
putForCreate(e.getKey(), e.getValue());
}
}
/**
* 将当前数据复制到容量更大的数组中。
* 该方法在存储数量达到临界值时自动被调用
*
* 如果当前容量已达到最大值,该方法不在调整map容量大小,但会设置扩容临界值为Integer.MAX_VALUE。
* 这具有防止将来调用的效果
*/
void resize(int newCapacity) {
// 如果旧数组到达最大值,设置扩容临界值为Integer.MAX_VALUE
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
//创建指定容量的新数组存储旧数据
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
//重新设置扩容临界值
threshold = (int)(newCapacity * loadFactor);
}
/**
* Transfers all entries from current table to newTable.
* 将所有数据从当前数组复制到新数组
*
* HashMap之所以不能保持元素的顺序有以下几点原因:
* 第一,插入元素的时候对元素进行哈希处理,不同元素分配到table的不同位置;
* 第二,容量拓展的时候又进行了hash处理;
* 第三,复制原表内容的时候链表被倒置。
*/
void transfer(Entry[] newTable) {
//保留原数组引用
Entry[] src = table;
//新的容量
int newCapacity = newTable.length;
//遍历源数组
for (int j = 0; j < src.length; j++) {
//获取元素e
Entry<K,V> e = src[j];
if (e != null) {
// 将原数组中的元素置为null
src[j] = null;
do {
//循环链表
Entry<K,V> next = e.next;
// 根据新的容量计算e在新数组中的索引
int i = indexFor(e.hash, newCapacity);
// 将e插入到newTable[i]指向的链表的头部
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
/**
*
* 复制所有指定map的映射到当前的map。
* 重复的映射会被替换。(即当前map中的key和指定参数map的key相同,值会被替换)
*/
public void putAll(Map<? extends K, ? extends V> m) {
int numKeysToBeAdded = m.size();
if (numKeysToBeAdded == 0)
return;
/*
* 为什么判断条件是numKeysToBeAdded,
* 不是(numKeysToBeAdded+table.length)>threshold?
*
* 这是一种保守的做法,明显地,我们应该在(numKeysToBeAdded+table.length)>threshold
* 的时候去拓展容量,但是考虑到将被添加的元素可能会有Key与原本存在的Key相同的情况,
* 所以采用保守的做法,避免拓展到过大的容量。
*/
if (numKeysToBeAdded > threshold) {
//计算目标容量
int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
//目标容量超过最大值, targetCapacity = MAXIMUM_CAPACITY;
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
//获取大于目标容量最小的2的冥,这就是信容量
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= 1;
//新容量大于当前数组长度,则扩容
if (newCapacity > table.length)
resize(newCapacity);
}
//遍历m中的数据,插入到当前的map中
for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<? extends K, ? extends V> e = i.next();
put(e.getKey(), e.getValue());
}
}
/**
*
* 根据key删除键值对
*/
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
/**
* 根据key删除键值对
*/
final Entry<K,V> removeEntryForKey(Object key) {
//计算key哈希
int hash = (key == null) ? 0 : hash(key.hashCode());
//计算数组索引
int i = indexFor(hash, table.length);
//链表前一个
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
//遍历链表,并删除
while (e != null) {
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
/**
* Special version of remove for EntrySet.
*/
final Entry<K,V> removeMapping(Object o) {
if (!(o instanceof Map.Entry))
return null;
Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
Object key = entry.getKey();
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
while (e != null) {
Entry<K,V> next = e.next;
if (e.hash == hash && e.equals(entry)) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
/**
*
* 清空map
*/
public void clear() {
modCount++;
Entry[] tab = table;
//清空数组
for (int i = 0; i < tab.length; i++)
tab[i] = null;
size = 0;
}
/**
*
* 是否包含指定值
*
*/
public boolean containsValue(Object value) {
//value为空
if (value == null)
return containsNullValue();
//遍历数组和链表(双重循环,较耗时)
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))
return true;
return false;
}
/**
*
* 是否包含为null的value
*/
private boolean containsNullValue() {
//遍历数组和链表(双重循环,较耗时)
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (e.value == null)
return true;
return false;
}
/**
* Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
* values themselves are not cloned.
*
* 克隆(只复制引用)
*
*/
public Object clone() {
HashMap<K,V> result = null;
try {
//创建一个空的Map
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// assert false;
}
result.table = new Entry[table.length];
result.entrySet = null;
result.modCount = 0;
result.size = 0;
result.init();
//将当前的键值对插入到新的Map
result.putAllForCreate(this);
return result;
}
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
//对下一个节点的引用
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
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;
//返回是旧的Value
return oldValue;
}
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();
// Key相等且Value相等则两个Entry相等
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是Key的hashCode和Value的hashCode的异或的结果
public final int hashCode() {
return (key==null ? 0 : key.hashCode()) ^
(value==null ? 0 : value.hashCode());
}
// 覆写toString方法,方便调试和查看输出
public final String toString() {
return getKey() + "=" + getValue();
}
/**
* 当调用put(k,v)方法存入键值对时,如果k已经存在,则该方法被调用。
* (没有函数体、default作用域,why?)
*/
void recordAccess(HashMap<K,V> m) {
}
/**
* 当Entry被从HashMap中移除时被调用。
* (没有函数体、default作用域,why?)
*/
void recordRemoval(HashMap<K,V> m) {
}
}
/**
*
* 根据指定的键,值和哈希码添加新条目到指定的容器
*
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
//获取链表头结点
Entry<K,V> e = table[bucketIndex];
//在链表头插入新节点,next指向原来的头结点
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
//如果size达到扩容临界值,则扩容
if (size++ >= threshold)
resize(2 * table.length);
}
/**
* Like addEntry except that this version is used when creating entries
* as part of Map construction or "pseudo-construction" (cloning,
* deserialization). This version needn't worry about resizing the table.
*
* Subclass overrides this to alter the behavior of HashMap(Map),
* clone, and readObject.
*/
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
size++;
}
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
//设置next指向数组第一项
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
//迭代过程中map被修改,抛出异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//获取下一项引用
Entry<K,V> e = next;
//为空,抛出异常
if (e == null)
throw new NoSuchElementException();
//(next引用指向下一项的下一项)如果下一项为链表的最后一项,则执行if里面代码(next指向数组的下一个非空索引)
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
//将当前应用执行下一项,并返回
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
private final class ValueIterator extends HashIterator<V> {
public V next() {
return nextEntry().value;
}
}
private final class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}
// Subclass overrides these to alter behavior of views' iterator() method
Iterator<K> newKeyIterator() {
return new KeyIterator();
}
Iterator<V> newValueIterator() {
return new ValueIterator();
}
Iterator<Map.Entry<K,V>> newEntryIterator() {
return new EntryIterator();
}
// Views
private transient Set<Map.Entry<K,V>> entrySet = null;
/**
* Returns a {@link Set} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own <tt>remove</tt> operation), the results of
* the iteration are undefined. The set supports element removal,
* which removes the corresponding mapping from the map, via the
* <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
* operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
* operations.
*/
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
private final class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
HashMap.this.clear();
}
}
/**
* Returns a {@link Collection} view of the values contained in this map.
* The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. If the map is
* modified while an iteration over the collection is in progress
* (except through the iterator's own <tt>remove</tt> operation),
* the results of the iteration are undefined. The collection
* supports element removal, which removes the corresponding
* mapping from the map, via the <tt>Iterator.remove</tt>,
* <tt>Collection.remove</tt>, <tt>removeAll</tt>,
* <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
* support the <tt>add</tt> or <tt>addAll</tt> operations.
*/
public Collection<V> values() {
Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));
}
private final class Values extends AbstractCollection<V> {
public Iterator<V> iterator() {
return newValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
HashMap.this.clear();
}
}
/**
*
* 获取键值对value集合
*
* @return a set view of the mappings contained in this map
*/
public Set<Map.Entry<K,V>> entrySet() {
return entrySet0();
}
/**
* 获取键值对value集合(获得一个代理类)
*/
private Set<Map.Entry<K,V>> entrySet0() {
Set<Map.Entry<K,V>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
/**
* 代理类(没有定义自己的数据,通过迭代器直接遍历map中的数组链表)
*/
private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public Iterator<Map.Entry<K,V>> iterator() {
//该代理通过迭代器遍历map数据,本身不存储数据
return newEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<K,V> e = (Map.Entry<K,V>) o;
//调用外部类的getEntry方法
Entry<K,V> candidate = getEntry(e.getKey());
return candidate != null && candidate.equals(e);
}
public boolean remove(Object o) {
return removeMapping(o) != null;
}
public int size() {
return size;
}
public void clear() {
HashMap.this.clear();
}
}
/**
* Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
* serialize it).
*
* @serialData The <i>capacity</i> of the HashMap (the length of the
* bucket array) is emitted (int), followed by the
* <i>size</i> (an int, the number of key-value
* mappings), followed by the key (Object) and value (Object)
* for each key-value mapping. The key-value mappings are
* emitted in no particular order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
Iterator<Map.Entry<K,V>> i = (size > 0) ? entrySet0().iterator() : null;
//调用默认的序列化流(序列化threshold, loadfactor等私有变量)
s.defaultWriteObject();
// 序列化数组长度
s.writeInt(table.length);
// 序列化键值对数
s.writeInt(size);
// 序列化键值对值(非引用)
if (i != null) {
while (i.hasNext()) {
Map.Entry<K,V> e = i.next();
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
}
}
private static final long serialVersionUID = 362498820763181265L;
/**
* 反序列化
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// 根据私有成员创建HashMap
s.defaultReadObject();
//根据数组长度初始化数组
int numBuckets = s.readInt();
table = new Entry[numBuckets];
//钩子方法(子类如果要在初始化之前处理某些业务,可覆写该方法)
init(); // Give subclass a chance to do its thing.
//读取要存储键值对的数量
int size = s.readInt();
// 根据键值对数量从流中循环读取并建立键值对
for (int i=0; i<size; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putForCreate(key, value);
}
}
// These methods are used when serializing HashSets
int capacity() { return table.length; }
float loadFactor() { return loadFactor; }
}