集合源码解析三:HashMap

版权声明:欢迎转载,转载请标明来源 https://blog.csdn.net/weixin_41973131/article/details/88951275

一 简介

HashMap支持存储空的key或空的value,并且不保证存储的元素按顺序排放。它与Hashtable基本相似,只是不支持并发操作。

对于get、and、put能操作能够实现常数级别的性能,遍历该集合的性能与HashMap的capacity与load factor成比例,所以,尽量不要设置太高的capacity或太小的load factor。

请注意HashMap的实现不支持同步,如果存在多个线程对HashMap进行操作。那么应当在对象外部进行同步,否则应该在一开始时就是用synchronizedMap(new HashMap(…))。

在迭代器Iterator被创建后,如果此时对HashMap进行结构性的操作(add、remove),则会抛出ConcurrentModificationException异常,除非是调用Iterator的remove方法。

二 成员变量

HashMap实现了Map接口,在语法层面上继承Map接口是多余的,这样做是为了让别人了解HashMap是属于Map体系。并且由AbstractMap提供了部分的实现,Cloneable代表该对象支持克隆,Serializable说明该对象支持序列化,即支持将数据转化存储到硬盘等介质中。

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

下面是该对象的成员变量:

	// 默认的初始化容量,它的值总是2的幂次方
	static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 
	// 最大能够运行的容量,它的值总是2的幂次方
	static final int MAXIMUM_CAPACITY = 1 << 30;

	// 默认装载因子
	static final float DEFAULT_LOAD_FACTOR = 0.75f;


	// 当好多bin被映射到同一个桶时,如果这个桶中bin的数量小于TREEIFY_THRESHOLD当然不会转化成树形结构存储;如果这个桶中bin的数量大于了 TREEIFY_THRESHOLD ,但是capacity小于MIN_TREEIFY_CAPACITY 则依然使用链表结构进行存储,此时会对HashMap进行扩容;如果capacity大于了MIN_TREEIFY_CAPACITY ,则会进行树化。

	// 由链表转换为红黑树阈值,默认为8
	// 通过柏松分布计算出当阀值为8时,概率分布为0.0001,概率极小,而8之前的概率接近于1
	static final int TREEIFY_THRESHOLD = 8;

	// 由红黑树变为链表阈值,默认为6,该值必须必TREEIFY_THRESHOLD小,至多为6
	static final int UNTREEIFY_THRESHOLD = 6;

	// 应该至少设置为4 * TREEIFY_THRESHOLD, 用以避免在扩容和树化阀值之间产生冲突
	// 转换树形结构的所需的最小容量,默认为64
	static final int MIN_TREEIFY_CAPACITY = 64;

	// 该表在第一次使用时被初始化,并且按照需要重新设置大小。长度永远是2的幂。在一些操作中允许table的长度为0
    transient Node<K,V>[] table;

	// 保存缓存entrySet()
    transient Set<Map.Entry<K,V>> entrySet;

    // 此映射中包含的键值映射的数量。
    transient int size;

	// 每次进行结构性修改时候会自增该值。
    transient int modCount;

	// threshold = capacity * loadFactor,当Size>=threshold的时候,那么就要考虑对数组的扩增
	int threshold;

	// loadFactor加载因子是控制数组存放数据的疏密程度,loadFactor越趋近于1,那么 数组中存放的数据也就越多,就是会让链表的长度增加。loadFactor越小,也就是趋近于0,数组中存放的数据也就越少
    final float loadFactor;

三 基础节点

static class Node<K,V> implements Map.Entry<K,V> {
    // 利用key生成的哈希值
    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; }

    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;
        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;
    }
}
	// 利用key生成哈希值
	static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); // 前16位不变,低16位与高16位异或作为key的最终hash值。
    }

    // 当x的类型为X,且X直接实现了Comparable接口(比较类型必须为X类本身)时,返回x的运行时类型;否则返回null。
    static Class<?> comparableClassFor(Object x) {
        // x是否继承或实现Comparable
        if (x instanceof Comparable) {
            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
            // 返回该对象的运行时类型并判断该类型是否为String类型
            if ((c = x.getClass()) == String.class) // 绕过检查
                return c;
            // 返回该对象运行时类型实现的接口并判断是否为null,即必须是自己实现的接口
            if ((ts = c.getGenericInterfaces()) != null) {
                for (int i = 0; i < ts.length; ++i) {
                    // ParameterizedType是Type接口的子接口,表示参数化的类型,即实现了泛型参数的类型。判断接口是否实现泛型参数。
                    // getRawType()方法返回声明了这个类型的类或接口,也就是去掉了泛型参数部分的类型对象。
                    // 判断该类是否实现了泛型化的Comparable接口
                    // getActualTypeArguments()以数组的形式返回泛型参数列表。当传入的是真实类型时,打印的是全类名。当传入的是另一个新声明的泛型参数时 ,打印的是代表该泛型参数的符号。
                    
                    if (((t = ts[i]) instanceof ParameterizedType) &&
                        ((p = (ParameterizedType)t).getRawType() ==
                         Comparable.class) &&
                        (as = p.getActualTypeArguments()) != null &&
                        as.length == 1 && as[0] == c) // 只有一个泛型参数,且该实现类型是该类型
                        return c; // 返回该类型
                }
            }
        }
        return null;
    }

	// 如果x的类型为kc,则返回k.compareTo(x),,否则返回0
    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
    static int compareComparables(Class<?> kc, Object k, Object x) {
        return (x == null || x.getClass() != kc ? 0 :
                ((Comparable)k).compareTo(x));
    }

	// >>>无符号右移,|=或
	// 用于找到大于等于initialCapacity的最小的2的幂
    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

	

构造函数

// 用指定的初始容量和装载因子构造一个空的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);
}

// 用指定的初始化容量和默认的装载因子构造一个空的HashMap实例
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

// 用默认的初始化容量和默认的装载因子构造一个空的HashMap实例
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

// 传入Map以构建一个新的HashMap实例,加载因子为默认的加载因子
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}

基本API

    // 实现Map.putAll 和 Map的构造器
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            // 实例未初始化时
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F; // ft即table此时所需capacity
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?  // 防止过界
                         (int)ft : MAXIMUM_CAPACITY);
                // 计算得到的t大于阈值,则初始化阈值
                if (t > threshold)
                    threshold = tableSizeFor(t);  // 找到大于等于t的最小的2的幂
            }
            // 已初始化,并且m元素个数大于阈值,进行扩容处理
            else if (s > threshold)
                resize();
            // 遍历m.entrySet并逐一赋值给新的HashMap实例
            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);
            }
        }
    }

    // 返回此映射中的键值映射的数量。
    public int size() {
        return size;
    }

    // 当该map实例中没有键值映射时返回true
    public boolean isEmpty() {
        return size == 0;
    }

    // 如果map中包含指定key的映射,则返回它的value,否则返回NULL
    // 返回NULL可能是map实例中不包含该键,也可能是该键对应的值为NULL
    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        // 列表不为空且至少拥有一个结点
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            // 检查第一个结点的键是否为key,是则返回key
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            // 桶中不止一个元素
            if ((e = first.next) != null) {
                // 在树中拿取
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                // 在列表中拿取          
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

    // 如果该map包含所指定值的映射则返回true
    public boolean containsKey(Object key) {
        return getNode(hash(key), key) != null;
    }

    // 在该map中将指定的key与指定的value关联起来。如果该map之前包含了该键的映射,那么之前的value将会被替代
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        // table未初始化或者长度为0,进行扩容。n为扩容后的数组长度
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // (n - 1) & hash 确定元素存放在哪个桶中,桶为空,新生成结点放入桶中(此时,这个结点是放在数组中)
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        // 桶中已经存在元素
        else {
            Node<K,V> e; K k;
            // 比较桶中第一个元素(数组中的结点)的hash值相等,key相等
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                // 将第一个元素赋值给e
                e = p;
            // hash值不相等或key不相等,判断是否为红黑树结点
            else if (p instanceof TreeNode)
                // 放入树中
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            // 为链表结点
            else {
                // 拉链法
                // 遍历到链表的最末端并插入结点
                for (int binCount = 0; ; ++binCount) {
                    // 到达链表尾部
                    if ((e = p.next) == null) {
                        // 在链表尾部插入新结点
                        p.next = newNode(hash, key, value, null);
                        // 结点数量达到阀值,转化为红黑树
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // 判断链表中结点的key值与插入的元素的key值是否相等
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break; // 相等则跳出循环
                    p = e; // 用以推动链表的指针指向
                }
            }
            // 表示在桶中找到key
            if (e != null) {
                // 取得旧值
                V oldValue = e.value;
                // onlyIfAbsent为false或者旧值为null
                if (!onlyIfAbsent || oldValue == null)
                    // 用新值替换旧值
                    e.value = value;
                // 访问后回调
                afterNodeAccess(e);
                // 返回旧值
                return oldValue;
            }
        }
        // 增加结构性修改次数
        ++modCount;
        // 如果大小超过阀值则拓容
        if (++size > threshold)
            resize();
        // 插入后回调
        afterNodeInsertion(evict);
        return null;
    }

    // 初始化或加倍表大小。如果为空,则根据字段阈值中持有的初始容量目标进行分配。否则,因为我们使用的是二次幂,所以每个bin中的元素要么保持在相同的索引中,要么在新表中以两个偏移量的幂移动。
    final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
            // 超过最大值就不再扩容
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            // 没超过最大值并且大于等于默认初始化容量即16,就扩充为原来的2倍
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // 加倍阀值
        }
        else if (oldThr > 0) // 容量设置为阈值
            newCap = oldThr;
        else {               // 容量设置为默认容量,阀值设置为加载因子*默认容量,该分支中oldTable为0
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        // 阀值为0 当oldThr > 0分支触发时,newThr为0
        if (newThr == 0) {
            // 阀值为新容量*加载因子,若大于2^30则按2^30算
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        // 将阀值设置为更改后的阀值
        threshold = newThr;
        // 按照新容量大小初始化列表
        @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {
            // 把每个bucket都移动到新的buckets中
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    // 如果该存储桶里面只有一个bin, 就直接将它放到新表的目标位置
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    // 如果该存储桶里面存的是红黑树, 则拆分树
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        // 按顺序遍历该存储桶位置上的链表中的节点.
                        do {
                            next = e.next;
                            // 顺序遍历该存储桶上的链表的每个节点, 如果 (e.hash & oldCap) == 0, 我们就将节点放入lo链表, 否则, 放入hi链表.
                            // 原索引
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            // 原索引+oldCap
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        // 如果lo链表非空, 就把整个lo链表放到新table的j位置上 
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        // 如果hi链表非空, 就把整个hi链表放到新table的j+oldCap位置上
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

	// 将链表转化为红黑树
    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        // 当列表为空或者列表的大小未达到红黑树的转化阀值时,进行扩容
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        // 要插入的桶位置第一个元素不为空
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            // 遍历链表
            do {
                // 将链表结点转化为树结点
                TreeNode<K,V> p = replacementTreeNode(e, null);
                if (tl == null)
                    // 头结点
                    hd = p;
                else {
                    // 将当前结点的前结点
                    p.prev = tl;
                    // 设置前结点的下一个结点
                    tl.next = p;
                }
                // 记录当前结点
                tl = p;
            } while ((e = e.next) != null);
            // 到目前为止 也只是把Node对象转换成了TreeNode对象,把单向链表转换成了双向链表
            // 把转换后的双向链表,替换原来位置上的单向链表
            if ((tab[index] = hd) != null)
                // 继续转换
                hd.treeify(tab);
        }
    }

	// 将所有映射从指定映射复制到此映射,对于相同的key会覆盖其映射。
    public void putAll(Map<? extends K, ? extends V> m) {
        putMapEntries(m, true);
    }

	// 如果存在,则从此映射中删除指定键的映射。删除成功则返回所删除键的映射,否则返回null
    public V remove(Object key) {
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }

	// 移除某结点
	// hash:key键的hash值,key/value:键值对,matchValeu:如果为真,只有当值相等时才移除。
	// movable:如果为false,则在删除时不要移动其他节点。
    final Node<K,V> removeNode(int hash, Object key, Object value,
                               boolean matchValue, boolean movable) {
        Node<K,V>[] tab; Node<K,V> p; int n, index;
        // 列表不为空且对应桶中至少存在一个结点
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {
            Node<K,V> node = null, e; K k; V v;
            // 判断第一个结点的键是否与指定key相同
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;
            // 判断桶中是否存在第二个结点
            else if ((e = p.next) != null) {
                // 判断该节点是否为树节点
                if (p instanceof TreeNode)
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                else {
                    // 遍历链表直到找到键与指定key相同的结点
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
            
            // 上述操作后,node结点为需要移除的结点
            // node已找到并且符合(不需要验证映射 || 映射引用相等 || 映射不为空并且相等)
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
                // node为树结点
                if (node instanceof TreeNode)
                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                // node为桶的第一个结点
                else if (node == p)
                    tab[index] = node.next;
                // 将node加载链表尾端
                else
                    p.next = node.next;
                // 增加结构性操作次数,减少大小
                ++modCount;
                --size;
                // 删除回调
                afterNodeRemoval(node);
                // 返回被删除的结点
                return node;
            }
        }
        return null;
    }

    /**
     * Removes all of the mappings from this map.
     * The map will be empty after this call returns.
     */
	// 移除map中所有的映射,调用该方法后map实例将会被清空
    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }

	// 如果该映射映射到指定值的一个或多个键,则返回true。
    public boolean containsValue(Object value) {
        Node<K,V>[] tab; V v;
        if ((tab = table) != null && size > 0) {
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value ||
                        (value != null && value.equals(v)))
                        return true;
                }
            }
        }
        return false;
    }

Set操作

	// 返回此映射中所包含的键的 set 视图。该集合受映射的支持,所以映射的变化也反映在该集合中,反之亦然。该集合支持元素的移除,通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作,从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
    public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

	// keySet内部类,继承了AbstractSet的实现
    final class KeySet extends AbstractSet<K> {
        public final int size()                 { return size; } // 所包含键的数量
        public final void clear()               { HashMap.this.clear(); }  // 清空Set
        public final Iterator<K> iterator()     { return new KeyIterator(); } // 创建迭代器
        public final boolean contains(Object o) { return containsKey(o); } // 判断是否包含指定对象
        // 移除指定对象
        public final boolean remove(Object key) {
            return removeNode(hash(key), key, null, false, true) != null;
        }
        
        // 构造分割迭代器
        public final Spliterator<K> spliterator() {
            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        
        // 遍历Set并消费元素, 不能修改元素
        public final void forEach(Consumer<? super K> 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.key);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }

	// 返回此映射中所包含的值的 Collection 视图。该集合受映射的支持,所以映射的变化也反映在该集合中,反之亦然。该集合支持元素的移除,通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作,从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
    public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new Values();
            values = vs;
        }
        return vs;
    }

	// Values内部类,继承了AbstractCollection的实现
    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();
            }
        }
    }

	// 返回此映射中所包含的映射的 Set 视图。该集合受映射的支持,所以映射的变化也反映在该集合中,反之亦然。该集合支持元素的移除,通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作,从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }

	// EntrySet内部类,继承了AbstractSet的实现
    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();
            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();
            }
        }
    }

JDK8映射扩展方法

此处用到大量函数式接口,若有不理解的同学请查询另一篇有关函数式接口的博客。

	// 返回map实例中指定key的值,若无则返回defaultValue
	@Override
    public V getOrDefault(Object key, V defaultValue) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
    }

	// 当指定键值对存在时才进行更改并返回旧值
    @Override
    public V putIfAbsent(K key, V value) {
        return putVal(hash(key), key, value, true, true);
    }

	// 移除指定的键值对并返回操作结果
    @Override
    public boolean remove(Object key, Object value) {
        return removeNode(hash(key), key, value, true, true) != null;
    }

	// 对于map实例中指定的key键,只有当指定的旧值与其相同才会使用新值进行替换
    @Override
    public boolean replace(K key, V oldValue, V newValue) {
        Node<K,V> e; V v;
        if ((e = getNode(hash(key), key)) != null &&
            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
            e.value = newValue;
            // 回调
            afterNodeAccess(e);
            return true;
        }
        return false;
    }
	
	// 用指定的value替换映射中键key所对应的值,并返回替换前的值。
    @Override
    public V replace(K key, V value) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) != null) {
            V oldValue = e.value;
            e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
        return null;
    }

	// 如果指定的key不存在,则通过指定的K -> V计算出新的值设置为key的值。
    @Override
    public V computeIfAbsent(K key,
                             Function<? super K, ? extends V> mappingFunction) {
        if (mappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node<K,V>[] tab; Node<K,V> first; int n, i;
        int binCount = 0; // 统计桶内链表长度
        TreeNode<K,V> t = null;
        Node<K,V> old = null;
        // 映射大小超过阀值或者映射为空时,对map进行扩容。
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        // key值的hash所对应桶的第一个元素不为空
        if ((first = tab[i = (n - 1) & hash]) != null) {
            // 第一个结点时树节点
            if (first instanceof TreeNode)
                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
            // 链表结点
            else {
                Node<K,V> e = first; K k;
                // 遍历链表
                do {
                    // 结点e的键等于指定键的值
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k)))) {
                        // 记录查询到的结点e
                        old = e;
                        break;
                    }
                    ++binCount;
                } while ((e = e.next) != null);
            }
            V oldValue;
            // 已经查询到指定的key对应的结点
            if (old != null && (oldValue = old.value) != null) {
                // 回调
                afterNodeAccess(old);
                return oldValue;
            }
        }
        // 若执行到此处则说明该映射中不存在指定的key
        // 消费key
        V v = mappingFunction.apply(key);
        // 处理key后得到的值v为空,即计算不出新值
        if (v == null) {
            return null;
        // 存在指定key对应的值,但该值old.value为null
        } else if (old != null) {
            old.value = v;
            afterNodeAccess(old);
            return v;
        }
        // 映射中不存在指定的key,将键值对存放到树中
        else if (t != null)
            // 将键值对放入树结点中s
            t.putTreeVal(this, tab, hash, key, v);
        // 映射中不存在指定的key, 将键值对存放到链表中
        else {
            tab[i] = newNode(hash, key, v, first);
            // 判断加入结点后链表长度是否达到链表装换红黑树阀值
            if (binCount >= TREEIFY_THRESHOLD - 1)
                treeifyBin(tab, hash);
        }
        ++modCount;
        ++size;
        // 空方法,只允许LinkedHashMap实现
        afterNodeInsertion(true);
        return v;
    }

	// 如果指定的key存在,则通过指定的K, V -> V计算出新的值设置为key的值并返回新值,如果不存在则移除该键值对
    public V computeIfPresent(K key,
                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        if (remappingFunction == null)
            throw new NullPointerException();
        Node<K,V> e; V oldValue;
        int hash = hash(key);
        // 映射中存在指定的key,并且其对应的值不为null
        if ((e = getNode(hash, key)) != null &&
            (oldValue = e.value) != null) {
            // 消费key, oldValue
            V v = remappingFunction.apply(key, oldValue);
            // 设置新值
            if (v != null) {
                e.value = v;
                // 回调,只有LinkedHashMap实现
                afterNodeAccess(e);
                return v;
            }
            else
                // 移除该键值对
                removeNode(hash, key, null, false, true);
        }
        return null;
    }

	// 通过指定的K, V -> V计算出新的值设置为key的值并返回新值,若存在指定key所对应的值,则V为该值,否则V为null
    @Override
    public V compute(K key,
                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        if (remappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node<K,V>[] tab; Node<K,V> first; int n, i;
        int binCount = 0;
        TreeNode<K,V> t = null;
        Node<K,V> old = null;
        // 大小超过阀值或者列表为空,需要扩容。
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        // key值的hash所对应桶的第一个元素不为空
        if ((first = tab[i = (n - 1) & hash]) != null) {
            // 桶的第一个元素是树结点
            if (first instanceof TreeNode)
                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
            else {
                Node<K,V> e = first; K k;
                // 遍历链表
                do {
                    // 找到与指定key相同的键
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k)))) {
                        old = e;
                        break;
                    }
                    ++binCount;
                } while ((e = e.next) != null);
            }
        }
        V oldValue = (old == null) ? null : old.value;
        // 利用key与value的值得到新值
        V v = remappingFunction.apply(key, oldValue);
        // 已找到指定key的结点
        if (old != null) {
            // 得出的key不为空
            if (v != null) {
                old.value = v;
                afterNodeAccess(old);
            }
            else
                removeNode(hash, key, null, false, true);
        }
        // 映射中不存在指定key的结点并且新值不为空
        else if (v != null) {
            // 桶中第一个结点为树结点
            if (t != null)
                // 将新的键值对存入红黑树中
                t.putTreeVal(this, tab, hash, key, v);
            else {
                // 将新的键值对存入链表中
                tab[i] = newNode(hash, key, v, first);
                // 若链表数量超过阀值,则将链表装换为红黑树
                if (binCount >= TREEIFY_THRESHOLD - 1)
                    treeifyBin(tab, hash);
            }
            ++modCount;
            ++size;
            afterNodeInsertion(true);
        }
        return v;
    }

	// 如果指定的key不存在,则设置指定的value值,否则根据key的旧的值oldvalue,value计算出新的值newValue, 如果newValue为null, 则删除该key,否则设置key的新值
    @Override
    public V merge(K key, V value,
                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        if (value == null)
            throw new NullPointerException();
        if (remappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node<K,V>[] tab; Node<K,V> first; int n, i;
        int binCount = 0;
        TreeNode<K,V> t = null;
        Node<K,V> old = null;
        // 大小超过阀值或者列表为空,需要扩容。
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        // key值的hash所对应桶的第一个元素不为空
        if ((first = tab[i = (n - 1) & hash]) != null) {
            if (first instanceof TreeNode)
                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
            else {
                Node<K,V> e = first; K k;
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k)))) {
                        old = e;
                        break;
                    }
                    ++binCount;
                } while ((e = e.next) != null);
            }
        }
        
        // 找到指定key对应的结点
        if (old != null) {
            V v;
            // 结点的value不为空
            if (old.value != null)
                // 根据key的oldValue和value计算出新值
                v = remappingFunction.apply(old.value, value);
            else
                v = value;
            // 计算出来的新值或value不为空
            if (v != null) {
                // 更新结点的value
                old.value = v;
                afterNodeAccess(old);
            }
            else
                // 移除该结点
                removeNode(hash, key, null, false, true);
            return v;
        }
        // 映射中找不到指定的key且新value不为空
        if (value != null) {
            // 桶的结点为树型
            if (t != null)
                // 往树中插入新节点
                t.putTreeVal(this, tab, hash, key, value);
            else {
                // 往链表中插入结点
                tab[i] = newNode(hash, key, value, first);
                if (binCount >= TREEIFY_THRESHOLD - 1)
                    treeifyBin(tab, hash);
            }
            ++modCount;
            ++size;
            afterNodeInsertion(true);
        }
        return value;
    }

	// 遍历列表并按照(K, V) -> {}消费元素
    @Override
    public void forEach(BiConsumer<? super K, ? 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.key, e.value);
            }
            // 判断在遍历期间是否发生过结构性修改
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
	
	// 替换元素,按(K, V, V) -> {} 将K更换为V
    @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Node<K,V>[] tab;
        if (function == 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) {
                    e.value = function.apply(e.key, e.value);
                }
            }
            // 判断在遍历期间是否发生过结构性修改
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

克隆和序列化

	// 返回该HashMap实例的一个浅赋值,不复制键值对本身
    @SuppressWarnings("unchecked")
    @Override
    public Object clone() {
        HashMap<K,V> result;
        try {
            // 调用父类即AbstractMap的克隆方法
            result = (HashMap<K,V>)super.clone();
        } catch (CloneNotSupportedException e) {
            // 这不应该发生,因为我们是可克隆的
            throw new InternalError(e);
        }
        // 初始化数据
        result.reinitialize();
        // 将该HashMap实例中的所有Entrries复制进新的实例中
        result.putMapEntries(this, false);
        return result;
    }

    // 这些方法也用于序列化哈希集
    final float loadFactor() { return loadFactor; }
    
 	// 若列表不为空则返回列表的长度,否则返回列表的阀值
	final int capacity() {
        return (table != null) ? table.length :
            (threshold > 0) ? threshold :
            DEFAULT_INITIAL_CAPACITY;
    }

	// 将HashMap实例的状态保存到流中(即序列化)
    private void writeObject(java.io.ObjectOutputStream s)
        throws IOException {
        int buckets = capacity();
        // 写出阈值、负载因子和任何隐藏的东西
        s.defaultWriteObject();
        s.writeInt(buckets);
        s.writeInt(size);
        // 遍历并将所有键值对序列化
        internalWriteEntries(s);
    }

	// 从一个流中重新构造HashMap实例(反序列化)
    private void readObject(java.io.ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        // 读取阀值、负载因子和任何隐藏的东西
        s.defaultReadObject();
        // 初始化所有字段
        reinitialize();
        // 判断负载因子是否合法
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        s.readInt();                // 读取并忽略桶的数量
        int mappings = s.readInt(); // 读取映射的大小
        if (mappings < 0)
            throw new InvalidObjectException("Illegal mappings count: " +
                                             mappings);
        else if (mappings > 0) { // 如果为0,则使用默认值
            // 仅在内部使用给定的负载因子调整表的大小
            // 范围在0.25-4.0之间
            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
            // 列表此时所需的容量大小
            float fc = (float)mappings / lf + 1.0f;
            // 设置容量大小,容量最小为DEFAULT_INITIAL_CAPACITY,最大为MAXIMUM_CAPACITY,并且是2的幂
            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                       DEFAULT_INITIAL_CAPACITY :
                       (fc >= MAXIMUM_CAPACITY) ?
                       MAXIMUM_CAPACITY :
                       tableSizeFor((int)fc));
            // 内部阀值
            float ft = (float)cap * lf;
            // 若容量cap与阀值ft都小于MAXIMUM_CAPACITY则设置阀值为ft,否者设置为2^31-1
            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                         (int)ft : Integer.MAX_VALUE);

            // 检查Map.Entry[].class,因为它是最接近我们实际创建的public类型。
            SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);
            @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
            table = tab;

            // 读取键值对并将其放入HashMap中
            for (int i = 0; i < mappings; i++) {
                @SuppressWarnings("unchecked")
                    K key = (K) s.readObject();
                @SuppressWarnings("unchecked")
                    V value = (V) s.readObject();
                putVal(hash(key), key, value, false, false);
            }
        }
    }

(可分割)迭代器

通过实现HashIterator以及Spliterator,再继承各自的迭代器以实现键、值、键值对的(可分割s)迭代器

	// 哈希迭代器
	abstract class HashIterator {
        Node<K,V> next;        // 下一个返回的键值对
        Node<K,V> current;     // 当前键值对
        int expectedModCount;  // 用以快速失败
        int index;             // 当前位置

        // 构造器
        HashIterator() {
            expectedModCount = modCount;
            Node<K,V>[] t = table;
            current = next = null;
            index = 0;
            if (t != null && size > 0) { // 递进到第一个键值对
                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();
            // 如果下一个键值对为null并且列表不为null,则递进到下一个不为空的桶。否则指向下一个键值对
            if ((next = (current = e).next) == null && (t = table) != null) {
                do {} while (index < t.length && (next = t[index++]) == null);
            }
            return e;
        }

        // 移除当前指向的结点
        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;
            // 移除该结点
            removeNode(hash(key), key, null, false, false);
            // 由于removeNode会改变modCount,因此需要后面进行同步
            expectedModCount = modCount;
        }
    }
	
	// 键迭代器
    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(); }
    }

	// HashMap可分割迭代器
    static class HashMapSpliterator<K,V> {
        final HashMap<K,V> map;
        Node<K,V> current;          // 当前结点
        int index;                  // 起始位置(包含),advance/spilt操作时会修改
        int fence;                  // 结束位置(不包含),-1表示到最后一个元素
        int est;                    // 当前分割的map大小
        int expectedModCount;       // 用以检查改变

		// 构建HashMap可分割迭代器s
        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;
        }

		// 获取结束位置, 在第一次使用时初始化fence和size    
        final int getFence() { // initialize fence and size on first use
            int hi;
            // fence < 0 表示fence指向最后一个元素 
            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;
        }

		// 估算大小
        public final long estimateSize() {
            getFence(); // 强制初始化
            // 返回大小
            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);
        }
	
		// 尝试切割出当前map段从中间到结尾的部分
        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);
        }

		// 遍历并消费片段内的元素
        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;
            // fence指向映射尾端,也代表第一次切割
            if ((hi = fence) < 0) {
                mc = expectedModCount = m.modCount;
                hi = fence = (tab == null) ? 0 : tab.length;
            }
            else
                mc = expectedModCount;
                
            // 如果列表不为空并且还有剩余元素,并且索引位置合法
            if (tab != null && tab.length >= hi &&
                (i = index) >= 0 && (i < (index = hi) || current != null)) {
                Node<K,V> p = current;
                current = null;
                // 遍历元素
                do {
                    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();
            }
        }

		// 如果存在没处理的数据,执行指定的代码并返回true;若不存在,直接返回false;只处理一个数据
        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++];
                    else {
                        K k = current.key;
                        current = current.next;
                        action.accept(k);
                        if (map.modCount != expectedModCount)
                            throw new ConcurrentModificationException();
                        return true;
                    }
                }
            }
            return false;
        }
		
		// 返回特征值。这里只会有2种结果。通过返回值能反应KeySpliterator当前状态。
        public int characteristics() {
            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
                Spliterator.DISTINCT;
        }
    }

	// 值可分割迭代器
    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) {
                mc = expectedModCount = m.modCount;
                hi = fence = (tab == null) ? 0 : tab.length;
            }
            else
                mc = expectedModCount;
            if (tab != null && tab.length >= hi &&
                (i = index) >= 0 && (i < (index = hi) || current != null)) {
                Node<K,V> p = current;
                current = null;
                do {
                    if (p == null)
                        p = tab[i++];
                    else {
                        action.accept(p.value);
                        p = p.next;
                    }
                } while (p != null || i < hi);
                if (m.modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }

		// 如果存在没处理的数据,执行指定的代码并返回true;若不存在,直接返回false;只处理一个数据
        public boolean tryAdvance(Consumer<? super V> 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++];
                    else {
                        V v = current.value;
                        current = current.next;
                        action.accept(v);
                        if (map.modCount != expectedModCount)
                            throw new ConcurrentModificationException();
                        return true;
                    }
                }
            }
            return false;
        }

		// 返回特征值。这里只会有2种结果。通过返回值能反应ValueSpliterator当前状态。
        public int characteristics() {
            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
        }
    }

	// 映射可分割迭代器
    static final class EntrySpliterator<K,V>
        extends HashMapSpliterator<K,V>
        implements Spliterator<Map.Entry<K,V>> {
        EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,
                         int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        public EntrySpliterator<K,V> trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid || current != null) ? null :
                new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
                                          expectedModCount);
        }

        public void forEachRemaining(Consumer<? super Map.Entry<K,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) {
                mc = expectedModCount = m.modCount;
                hi = fence = (tab == null) ? 0 : tab.length;
            }
            else
                mc = expectedModCount;
            if (tab != null && tab.length >= hi &&
                (i = index) >= 0 && (i < (index = hi) || current != null)) {
                Node<K,V> p = current;
                current = null;
                do {
                    if (p == null)
                        p = tab[i++];
                    else {
                        action.accept(p);
                        p = p.next;
                    }
                } while (p != null || i < hi);
                if (m.modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }

        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> 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++];
                    else {
                        Node<K,V> e = current;
                        current = current.next;
                        action.accept(e);
                        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;
        }
    }

LinkedHashMap的支持

// 以下的包保护方法设计来被LinkedHashMap重写,而不是子类不能够重写以下方法,

// 创建一个普通(非树结点)结点
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
    return new Node<>(hash, key, value, next);
}

// 用于将树节点转换为普通节点
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
    return new Node<>(p.hash, p.key, p.value, next);
}

// 创建一个树bin节点
TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
    return new TreeNode<>(hash, key, value, next);
}

// 将普通结点转化为树结点
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
    return new TreeNode<>(p.hash, p.key, p.value, next);
}

// 重写来初始化默认状态,可以被clone与readObject方法调用
void reinitialize() {
    table = null;
    entrySet = null;
    keySet = null;
    values = null;
    modCount = 0;
    threshold = 0;
    size = 0;
}

// LinkedHashMap的回调操作
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }

// Called only from writeObject, to ensure compatible ordering.
// 只能被writeObject调用,用来保证兼容顺序
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
    Node<K,V>[] tab;
    if (size > 0 && (tab = table) != null) {
        for (int i = 0; i < tab.length; ++i) {
            for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                s.writeObject(e.key);
                s.writeObject(e.value);
            }
        }
    }
}

树操作

	// 树桶的键值对, 继承LinkedHashMap,因此可以用作常规节点或链接节点的扩展。
    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;    // 链接的下个节点,用于删除  
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }

        /**
         * Returns root of tree containing this node.
         */
        // 返回包含该节点的根节点
        final TreeNode<K,V> root() {
            for (TreeNode<K,V> r = this, p;;) {
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }

 		// TreeNode既是一个红黑树结构,也是一个双链表结构
        // 保证树的根节点是该桶的第一个结点
        static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
            int n;
            // 根节点与列表不为空
            if (root != null && tab != null && (n = tab.length) > 0) {
                // 求出根节点在列表位置的索引
                int index = (n - 1) & root.hash;
                // 该桶的第一个结点
                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
                // 树的根节点不是第一个结点
                if (root != first) {
                    Node<K,V> rn;
                    // 将桶的第一个元素设为根节点,rn与rp脱离了结点???
                    tab[index] = root;
                    TreeNode<K,V> rp = root.prev;
                    if ((rn = root.next) != null)
                        ((TreeNode<K,V>)rn).prev = rp;
                    if (rp != null)
                        rp.next = rn;
                    if (first != null)
                        first.prev = root;
                    root.next = first;
                    root.prev = null;
                }
                // 检查是否发生结构性错误
                assert checkInvariants(root);
            }
        }

        // 使用给定的哈希值和键从根p开始查找节点。kc参数在第一次使用比较键时缓存comparableClassFor(key)。
        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
            TreeNode<K,V> p = this;
            do {
                int ph, dir; K pk;
                TreeNode<K,V> pl = p.left, pr = p.right, q;
                if ((ph = p.hash) > h)
                    p = pl;
                else if (ph < h)
                    p = pr;
                // 以下为ph == h  
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p; // 找到则返回
                // 只有<=1棵子树情况  
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                // 有两棵子树,且是Comparable,则根据Comparable判断  
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                // 有两棵子树,但不是Comparable,这时只能去两个子树一起找(O(N))  
            	// 这地方循环和递归各处理一个子树  
                else if ((q = pr.find(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
            return null;
        }

        // 在当前节点所在的整个树(就是这个桶)里寻找key.equals(k)的节点 
        final TreeNode<K,V> getTreeNode(int h, Object k) {
            return ((parent != null) ? root() : this).find(h, k, null);
        }

        // 辅助方法用来给两个对象指定顺序 
     	// 用于处理hashCode相同又不是Comparable的情况
        static int tieBreakOrder(Object a, Object b) {
            int d;
            // 两个
            if (a == null || b == null ||
                // 如果不是同一个类,就根据类名排序  
                (d = a.getClass().getName().
                 compareTo(b.getClass().getName())) == 0)
                // 否则就根据原生(未重写)的hashCode来排序,System.identityHashCode是native实现  
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                     -1 : 1);
            return d;
        }

        // 将本节点所属的桶转化为树状结构
        final void treeify(Node<K,V>[] tab) {
            TreeNode<K,V> root = null;
            // 遍历该桶
            for (TreeNode<K,V> x = this, next; x != null; x = next) {
                next = (TreeNode<K,V>)x.next;
                x.left = x.right = null;
                if (root == null) {  // 根节点(第一次循环)
                    x.parent = null;
                    x.red = false;
                    root = x;
                }
                else {
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    for (TreeNode<K,V> p = root;;) {
                        int dir, ph;
                        K pk = p.key;
                        if ((ph = p.hash) > h)
                            dir = -1;
                        else if (ph < h)
                            dir = 1;
                        else if ((kc == null &&
                                  (kc = comparableClassFor(k)) == null) ||
                                 (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);

                        TreeNode<K,V> xp = p;
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
                            x.parent = xp;
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            root = balanceInsertion(root, x);
                            break;
                        }
                    }
                }
            }
            moveRootToFront(tab, root);
        }

        // 返回一个非树节点列表,替换从该节点链接的树节点。
        final Node<K,V> untreeify(HashMap<K,V> map) {
            Node<K,V> hd = null, tl = null;
            for (Node<K,V> q = this; q != null; q = q.next) {
                Node<K,V> p = map.replacementNode(q, null);
                if (tl == null)
                    hd = p;
                else
                    tl.next = p;
                tl = p;
            }
            return hd;
        }

        /**
         * Tree version of putVal.
         */
        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
                                       int h, K k, V v) {
            Class<?> kc = null;
            boolean searched = false;
            TreeNode<K,V> root = (parent != null) ? root() : this;
            for (TreeNode<K,V> p = root;;) {
                int dir, ph; K pk;
                if ((ph = p.hash) > h)
                    dir = -1;
                else if (ph < h)
                    dir = 1;
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                else if ((kc == null &&
                          (kc = comparableClassFor(k)) == null) ||
                         (dir = compareComparables(kc, k, pk)) == 0) {
                    if (!searched) {
                        TreeNode<K,V> q, ch;
                        searched = true;
                        if (((ch = p.left) != null &&
                             (q = ch.find(h, k, kc)) != null) ||
                            ((ch = p.right) != null &&
                             (q = ch.find(h, k, kc)) != null))
                            return q;
                    }
                    dir = tieBreakOrder(k, pk);
                }

                TreeNode<K,V> xp = p;
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                    Node<K,V> xpn = xp.next;
                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    xp.next = x;
                    x.parent = x.prev = xp;
                    if (xpn != null)
                        ((TreeNode<K,V>)xpn).prev = x;
                    moveRootToFront(tab, balanceInsertion(root, x));
                    return null;
                }
            }
        }

        // 移除树节点
        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
                                  boolean movable) {
            int n;
            if (tab == null || (n = tab.length) == 0)
                return;
            int index = (n - 1) & hash;
            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
            if (pred == null)
                tab[index] = first = succ;
            else
                pred.next = succ;
            if (succ != null)
                succ.prev = pred;
            if (first == null)
                return;
            if (root.parent != null)
                root = root.root();
            if (root == null || root.right == null ||
                (rl = root.left) == null || rl.left == null) {
                tab[index] = first.untreeify(map);  // too small
                return;
            }
            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
            if (pl != null && pr != null) {
                TreeNode<K,V> s = pr, sl;
                while ((sl = s.left) != null) // find successor
                    s = sl;
                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
                TreeNode<K,V> sr = s.right;
                TreeNode<K,V> pp = p.parent;
                if (s == pr) { // p was s's direct parent
                    p.parent = s;
                    s.right = p;
                }
                else {
                    TreeNode<K,V> sp = s.parent;
                    if ((p.parent = sp) != null) {
                        if (s == sp.left)
                            sp.left = p;
                        else
                            sp.right = p;
                    }
                    if ((s.right = pr) != null)
                        pr.parent = s;
                }
                p.left = null;
                if ((p.right = sr) != null)
                    sr.parent = p;
                if ((s.left = pl) != null)
                    pl.parent = s;
                if ((s.parent = pp) == null)
                    root = s;
                else if (p == pp.left)
                    pp.left = s;
                else
                    pp.right = s;
                if (sr != null)
                    replacement = sr;
                else
                    replacement = p;
            }
            else if (pl != null)
                replacement = pl;
            else if (pr != null)
                replacement = pr;
            else
                replacement = p;
            if (replacement != p) {
                TreeNode<K,V> pp = replacement.parent = p.parent;
                if (pp == null)
                    root = replacement;
                else if (p == pp.left)
                    pp.left = replacement;
                else
                    pp.right = replacement;
                p.left = p.right = p.parent = null;
            }

            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);

            if (replacement == p) {  // detach
                TreeNode<K,V> pp = p.parent;
                p.parent = null;
                if (pp != null) {
                    if (p == pp.left)
                        pp.left = null;
                    else if (p == pp.right)
                        pp.right = null;
                }
            }
            if (movable)
                moveRootToFront(tab, r);
        }

        // 分裂树
        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
            TreeNode<K,V> b = this;
            // Relink into lo and hi lists, preserving order
            TreeNode<K,V> loHead = null, loTail = null;
            TreeNode<K,V> hiHead = null, hiTail = null;
            int lc = 0, hc = 0;
            for (TreeNode<K,V> e = b, next; e != null; e = next) {
                next = (TreeNode<K,V>)e.next;
                e.next = null;
                if ((e.hash & bit) == 0) {
                    if ((e.prev = loTail) == null)
                        loHead = e;
                    else
                        loTail.next = e;
                    loTail = e;
                    ++lc;
                }
                else {
                    if ((e.prev = hiTail) == null)
                        hiHead = e;
                    else
                        hiTail.next = e;
                    hiTail = e;
                    ++hc;
                }
            }

            if (loHead != null) {
                if (lc <= UNTREEIFY_THRESHOLD)
                    tab[index] = loHead.untreeify(map);
                else {
                    tab[index] = loHead;
                    if (hiHead != null) // (else is already treeified)
                        loHead.treeify(tab);
                }
            }
            if (hiHead != null) {
                if (hc <= UNTREEIFY_THRESHOLD)
                    tab[index + bit] = hiHead.untreeify(map);
                else {
                    tab[index + bit] = hiHead;
                    if (loHead != null)
                        hiHead.treeify(tab);
                }
            }
        }

红黑树方法

后面的红黑树方法大家有兴趣的可以看一下。这里就不过多解释了。(看到后面就不是很懂了,缓缓先)

思考

1 为什么需要hash()方法

为什么在key已经有hash值的情况下仍然需要hash()方法,可以看下以下方法:

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 
    }

从该代码中可以看出hash()是将key的哈希值的前16位不变,低16位与高16位异或作为key的最终hash值。

可是为什么需要这样做?

我们知道table的坐标定位方法如下:

n = table.length;
index = (n - 1) & hash;

但是因为table的长度是以2为幂的数值,类似于二进制数字10000,那么n - 1将导致index = 1111 & hash。学过或的会知道,此时会导致index的取值只与hash值的后数位有关,相当于这样的话会更容易导致碰撞。而使用低16位与高16位异或将增大hash值的随机性,可以有效减少哈希碰撞的概率。

2 为什么MAXIMUM_CAPACITY只为2^30

大家都知道Java环境的int为32字节,那么为什么MAXIMUM_CAPACITY最大只为2^30

首先在Java环境中,int类型没有无符号类型,因此最高位为符号位,这样一来实际上可以由正整数支配的数字只有2^31 - 1

在构造函数中有一句:

if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;

实际上可以说明HashMap在初始化时最大能够使用的容量是MAXIMUM_CAPACITY。

但是在因为继续增加元素而导致超过最大容量时。实例会调用resize()重新构建容量大小,此时:

if (oldCap >= MAXIMUM_CAPACITY) {
	threshold = Integer.MAX_VALUE;
    return oldTab;
}

Integer.MAX_VALUE的大小即为2^31 - 1,那么将threshold值改变成Integer.MAX_VALUE,说明以后不再拓容。

同时在HashMap的构造函数中有以下语句:

this.threshold = tableSizeFor(initialCapacity);

tableSizeFor()方法会将你的容量置为 2的k次方,因此最大的值应为2^30

3 tableSizeFor的操作

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

该方法是用于找到大于等于initialCapacity的最小的2的幂。

cap-1是为了防止当一开始cap为2的幂时,如果没有执行-1操作,则会导致得到的capacity变为cap的两倍。

接下来的我们分为三种情况进行讨论:

当cap为0时,n为-1,此时返回的capacity为1。

当cap为1时,n为0,此时经过无论都多少次右移与或操作,结果n还是0,因此最后会返回的capacity为1.

当cap不为1时,由于无论如何,cap的最左位肯定存在一位为1,因此我们假设一个cap数为1xxxxxx1,那么n即为1xxxxxx0。

n |= n >>> 1;时,n右移一位为01xxxxxx,与1xxxxxx0或操作后结果为:11xxxxxx

n |= n >>> 2;时,n右移两位为0011xxxx,与11xxxxxx或操作后结果为:1111xxxx

依次类推,由于一共位移为32位,而int类型的最大位数也为32位,因此n的最高位1后面的位数一定会全部置为1。即是2^k - 1(32>k>0)即在上面的例子中结果肯定是11111111。最后+1操作后capacity就是大于等于initialCapacity的最小的2的幂。

4 ((float)s / loadFactor)+1.0F 为啥要加1

解释1:先+1,看看是否超过了阈值,如果超过了阈值,就扩容,不加1的话,如果正好等于阈值就不会扩容。

解释2:弥补float与int转换、比较精度弥补。

5 resize()中e.hash & oldCap的设计

在前面中我们学过,HashMap中定位数组下标是采用如下方法的:

n = table.length;
index = (n - 1) & hash;

我们知道,容量的大小一定是2的幂,那么假设n=2^4=16。即n=10000n-1=1111

所以实际上index是在求hash码中后m位的值。我们假设hash码中后四位为abcd,那么1111 & abcd = abcd

当HashMap扩容后,即n>>1,此时n-1 = 11111,相比较我们知道每次扩容hash码所取的位数都会+1。

此时求与后无非存在两种情况:1abcd0abcd。其中后者与原来的值相等,前者为原值加上原来的容量大小(0abcd + 10000 = 1abcd)。

因此在resize()方法中根据e.hash & oldCap == 0,可看成xabcd & 10000判断键e在定位数组下标时会是哪种情况,若返回true则为后者,否者为前者,并将其分成两个链表进行存储。

最后若为0abcd这种情况则与扩容前的定位一致,则应将其放置在新列表的原索引j处

否则将其放置在新列表的j + oldCap处,因为对于1abcd & 11111 = 1abcd,而abcd + 10000 = 1abcd

总的来说:

  1. 每次扩容都会新建一个table, 新建的table的大小为原大小的2倍.
  2. 扩容时,会将原table中的节点re-hash到新的table中, 但节点在新旧table中的位置存在一定联系: 要么下标相同, 要么相差一个oldCap(原table的大小).

猜你喜欢

转载自blog.csdn.net/weixin_41973131/article/details/88951275