java容器 类HashMap源码分析

目录

简介

常量   默认初始容量,最大容量,默认负载因子,树化/反树化界限,最小树化容量

节点类  Node

静态的工具方法  hash(重要),comparableClassFor,compareComparables,tableSizeFor(较重要)

字段 table,entrySet,size,modCount,threshold,loadFactor

构造函数 4个(重要)

查询方法 size,isEmpty,get,getNode(重要),containsKey,containsValue

放入操作  put,putVal(重要),resize(重要),treeifyBin,putAll,putMapEntries

HashMap的构造方法,get,put总结

删除操作 remove,removeNode,clear

三个视图 keySet,values,entrySet

一堆覆盖了JDK8的Map的default方法 getOrDefault,putIfAbsent,remove,replace两个,computeXXX3个,merge,forEach,replaceAll

clone,writeObject,readObject

迭代器 HashIterator,KeyIterator,ValueIterator,EntryIterator

分割器 4个,如迭代器

被LinkedHashMap覆盖的方法   newNode2个(普通和树节点),replaceNode2个(普通和树节点),reinitialize,afterNodeXXX3个

树节点 TreeNode

jdk1.8和1.7之间HashMap的区别

数据结构

重要参数

声明1个 HashMap的对象

向HashMap添加数据(成对 放入 键 - 值对)

添加数据的流程如下

hash(key)

putVal(hash(key), key, value, false, true);

从HashMap中获取数据

对HashMap的其他操作

关于HashMap的其他问题

哈希表如何解决Hash冲突

为什么HashMap具备下述特点:键-值(key-value)都允许为空、线程不安全、不保证有序、存储位置随时间变化

为什么 HashMap 中 String、Integer 这样的包装类适合作为 key 键

HashMap 中的 key若 Object类型, 则需实现哪些方法?

HashMap和HashTable的理解与区别

父类不同

null值问题

线程安全性

遍历方式不同

初始容量不同

计算哈希值的方法不同


简介

/**
 * 

基于哈希表实现Map接口。 * 这个实现提供了所有的额外的map操作,并且允许null的value和null的key。 * (HashMap类与Hashtable大致相同,除了HashMap是非同步的,并且允许null)。 * 这个类不保证map的顺序,尤其是,他不保证顺序,会随着时间流逝,保持不变。 * *

这个实现为基础操作(get和put)实现了常量时间的性能,假设hash函数将元素均匀地分散到桶中。 * 对collection视图的迭代需要与HashMap实例的容量(桶的数量)正比的时间,来增加它的大小(key-value映射的数量)。 * 因此,如果迭代的性能很重要,不要设置初始的容量太大(或者负载因子过小) * *

HashMap的实例有着两个影响性能的参数:初始capacity和负载因子load factor。 * capacity是哈希表中桶的数量,初始capacity通常是哈希表创建后的容量。 * 负载因子load factor是指标,衡量哈希表的容量自动增加时,哈希表有多满。 * 当哈希表entry的数量,超过了,load factor * 此时的capacity,哈希表重新哈希 rehash * (就是内部的数据结构被重构),从而哈希表的桶的数量将近*2 * *

通常来说,默认的load factor 0.75,在时间和空间效率间提供了很好的权衡。 * 数值更高,会减少空间成本,但是增加了查找的成本(影响了大部分HashMap的操作,包括get和put)。 * (因为增加负载因子,减少空间成本,就更容易发生hash碰撞,同一个桶的数据更多,查找对应元素时间更长) * 设置map的处理容量时,应该考虑map中预期的entry的数量和负载因子,来最小化rehash操作的数量。 * 如果初始容量大于entry的最大数量/负载因子,不会发生rehash操作 * *

如果许多映射要被存在HashMap实例,使用一个足够大的容量来创建它, * 会让映射被存放的更有效率,而不是执行rehash来增大哈希表。 * 注意:使用许多有着相同的hashcode的key,会降低任何哈希表的效率。 * 为了改善影响,当key是Comparable的,这个类会使用key之间的比较顺序,来帮助断开连接。 * *

注意:这个实现不是同步的。 * 如果多线程并发地访问一个hashmap,并且至少一个线程结构上修改了map,必须在外部进行同步。 * (结构上的改变是增加,删除一个或多个元素, * 或者显式地改变依赖数组的大小,仅仅改变元素的值不会是一个结构上的改变) * 这通常是对将map装入内部的对象进行同步,来完成。 * *

如果没有这样的对象,列表应该使用Collections.synchronizedMap来包装它。 * 它通常该在创建时做,来防止意外对map的非同步访问。

 *   Map m = Collections.synchronizedMap(new HashMap(...));
* *

这个类所有的集合视图方法,返回的Iterator是快速失败的。 * 如果Iterator创建后,map在任何时间被结构上改变了, * 除了迭代器自己的remove和add方法外,迭代器会抛出ConcurrentModificationException。 * 因此,面对并发的改变,Iterator快速失败,十分干净, * 而不是在将来某个不确定的时间,冒着风险,做任意的,不确定性的操作。 * *

注意:不能保证Iterator的快速失败机制, * 因为,通常地说,在存在非同步的并发修改的情况下,不可能做出严格的保证。 * 快速失败的迭代器基于最大努力抛出ConcurrentModificationException。 * 因此,依赖于这个异常,写程序来保证正确性是错的, * 迭代器的快速失败机制,应该仅仅被用来探测bug * * * @param the type of keys maintained by this map * @param the type of mapped values * * @author Doug Lea * @author Josh Bloch * @author Arthur van Hoff * @author Neal Gafter * @see Object#hashCode() * @see Collection * @see Map * @see TreeMap * @see Hashtable * @since 1.2 */ public class HashMap extends AbstractMap implements Map, Cloneable, Serializable { private static final long serialVersionUID = 362498820763181265L; /* * 实现的说明。 * * 这个map通常作为一个基于桶的哈希表,但如果桶变得过于大,它们被改造为TreeNode的桶, * 每个的结构与TreeMap相似。 * 大多数方法使用通常的桶,但是当可适用时,转发给TreeNode的方法(只需要检查节点的类型) * TreeNode的桶可以被遍历,并被像其他的一样使用,但是当桶里的元素过多时,额外地支持更快地查找。 * 然而,在正常使用时,大多数的桶没有过多的元素,所以在方法中可能会延迟检查tree桶的存在。 * * 树桶,即元素都是TreeNode的桶,通常根据hashcode进行排序, * 但是如果两个元素的类都是事先了Comparable接口的类,使用它们的compareTo方法来排序。 * (我们保守地通过反射,来检查泛型类型来验证这一点——请参见comparableclassFor方法)。 * 增加了树桶的复杂性是值得的,即使在最坏的情况下,提供O(log n)的性能, * 当key有着不同的hashcode或者是可排序的。 * 因此,当hashCode方法返回的值是低离散分布的, * 或者许多key有着同一个hashcode(只要它们也是可比较的),性能优雅地下降。 * 如果这两种方法都不适用,我们可能浪费2倍的时间和空间。 * 但目前所知的唯一案例来自于糟糕的用户编程实践,这些实践已经非常缓慢,以至于没有什么区别。) * * 因为TreeNode的大小是普通节点的2倍,我们仅仅在桶中有着足够的节点时, * 才使用TreeNode,看TREEIFY_THRESHOLD。 * 并且当数量足够小时(因为删除或者resize),转为普通的桶。 * 在使用分布良好的hashcode时,很少使用树桶。 * 理想情况下,在随机的hashcode情况下,桶中节点的数量遵循泊松分布, * 默认调整阀值threshold为0.75,平均参数为0.5, * 经因为resize的粒度,存在较大差异。 * 无视差异,预期列表的长度为(exp(-0.5) * pow(0.5, k) /factorial(k)) * * 0: 0.60653066 * 1: 0.30326533 * 2: 0.07581633 * 3: 0.01263606 * 4: 0.00157952 * 5: 0.00015795 * 6: 0.00001316 * 7: 0.00000094 * 8: 0.00000006 * 更多的情况,1000万中少于1次 * * 树桶的root通常是它的第一个节点。 * 然而,有时(通常仅仅发生于Iterator.remove), * root可能是别的,但可以在其他地方通过TreeNode.root()来恢复。 * * 所有适用的内部方法接受hashcode来作为一个参数(通常有public的方法提供), * 允许它们来调用它们,而不是重算hashCode。 * 大多数内部方法也接受一个tab参数,那是当前的哈希表, * 但是在调整大小或者转换时,可能是新的或者旧的。 * * 当桶列表被树化,分割或者反树化,我们将它们保持在相同的关联访问/遍历顺序(就是Node.next), * 为了更好地在本地保存,并且稍微简化调用iterator.remove来分割和遍历。 * 当使用comparator来插入时,为了保持总体的顺序(或者尽可能接近)来保证重新平衡, * 我们比较类和identityHashCodes作为tie-breakers * * 由于子类LinkedHashMap的存在,普通和树模式之间的使用和转换是复杂的。 * 有关定义在插入、删除和访问时调用的钩子方法,请参见下面, * 这些方法允许LinkedHashMap内部保持独立于这些机制。 * (这还要求将map实例传递给一些可能创建新节点的实用程序方法。) * * 基于并行编程的、类似于ssa的编码风格有助于消除所有扭曲指针中的错误. */

java容器 类HashMap源码分析_第1张图片

java容器 类HashMap源码分析_第2张图片

节点类

java容器 类HashMap源码分析_第3张图片

内部视图类

java容器 类HashMap源码分析_第4张图片

迭代器

java容器 类HashMap源码分析_第5张图片

分割器

java容器 类HashMap源码分析_第6张图片

树节点

java容器 类HashMap源码分析_第7张图片

 

常量   默认初始容量,最大容量,默认负载因子,树化/反树化界限,最小树化容量

    /**
     * 默认的初始容量,1 << 4,16,必须是2的幂
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * 最大的容量,1 << 30,如果构造函数指定了一个更高的值时,使用。
     * 容量一定是2的幂,而且 <=  1<<30
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 如果构造器中,没有指定负载因子,负载因子的值,0.75
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * 桶的数量界限,桶使用树而不是列表。
     * 当加入一个元素到一个至少有这么多节点的桶时,桶被转换为树。
     * 这个值必须必2大,并且应该至少是8,以便桶收缩为普通桶时,树的移除的假定相合。
     * 加入这个节点到桶前,有8个,加入后,有9个节点,则树化桶
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * 桶的数量限制,在resize操作中,反树化桶。
     * 应该小于TREEIFY_THRESHOLD,至少为6,来与删除时,的收缩探测相合。
     * resize操作时,新的桶的节点数<=6,对桶反树化
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * 桶可以被树化的,最小的哈希表的容量。
     * (否则如果一个桶中有太多的节点时,表被resize)
     * 应该至少是4 * TREEIFY_THRESHOLD,来避免resize和树化之间的冲突。
     * 如果树化桶时,表的长度 < MIN_TREEIFY_CAPACITY=64,则进行resize操作,而不进行树化桶
     */
    static final int MIN_TREEIFY_CAPACITY = 64;

节点类  Node

    /**
     * 普通的哈希桶节点,给大部分entry使用。
     * (看下面TreeNode的子类和LinkedHashMap的Entry子类)
     * 节点与节点的关系,类似于linkedlist的Node,但是节点与节点之间是单向链表,不是双向的
     */
    static class Node implements Map.Entry {
    	// hash是 key.hashcode ^ (hashcode >>> 16) 即高位16位不变,低位16位与高位16位进行亦或运算。	
        final int hash; // hash是final的,根据构造函数传入
        final K key; // key是final的,根据构造函数传入
        V value; // value不是final,可以用setvalue改变
        Node next; // 有next的下一个节点,由此可见是类似于linkedlist的。
        // 但是只有next,没有prev,是单向的

        Node(int hash, K key, V value, Node 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;
                //key与value都相同,节点相同
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

静态的工具方法  hash(重要),comparableClassFor,compareComparables,tableSizeFor(较重要)

    /* ---------------- Static utilities -------------- */

    /**
     * 计算key.hashCode(),并且将高位的hash传递到低位(通过亦或XOR)。
     * 因为哈希表使用2的幂作为掩码,所以仅仅在当前掩码之上的位发生变动的hashcode,会永远冲突。(就是低位不变,高位变)
     * (已知的例子是float作为key,小表中保存连续的数字)
     * 所以,我们做一个转换,将高位bit的影响扩展到低位。
     * 这是在时间,空间和位的扩展质量之间的权衡。
     * 因为许多普通的hashcode的集合是合理地分布的。(所以不因为扩展而受益),
     * 并且因为我们使用树来处理桶中的巨量冲突,我们仅仅使用XOR改变位,以最便宜的可行方式来减少性能的亏损,
     * 同时包含了高位的影响,高位因为哈希表大小的限制,从来不会被用于计算之内。
     */
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        // null 为 0
        // 否则结果为 hashcode ^ (hashcode >>> 16) 即高位16位不变,低位16位与高位16位进行亦或运算。
    }

    /**
     * 返回x的类,如果它的类C是实现了Comparable < C > 接口的,否则返回null
     */
    static Class comparableClassFor(Object x) {
        if (x instanceof Comparable) {
            Class c; Type[] ts, as; Type t; ParameterizedType p;
            if ((c = x.getClass()) == String.class) // bypass checks
            	//如果运行时类型是String,直接返回
                return c;
            if ((ts = c.getGenericInterfaces()) != null) {
            	// ts为这个类直接实现的接口,对ts进行遍历
                for (int i = 0; i < ts.length; ++i) {
                    if (((t = ts[i]) instanceof ParameterizedType) &&
                        ((p = (ParameterizedType)t).getRawType() ==
                         Comparable.class) &&
                        (as = p.getActualTypeArguments()) != null &&
                        as.length == 1 && as[0] == c) // type arg is c
                    	//如果接口是Comparable,返回类c
                        return c;
                }
            }
        }
        //x不是Comparable接口的,直接返回null
        return null;
    }

    /**
     * 如果x匹配kc(k是筛选过的Comparable的类),返回k.compareTo(x),否则返回0.
     */
    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
    static int compareComparables(Class kc, Object k, Object x) {
    	// 如果x为null,或者x的类不是kc,返回0
        return (x == null || x.getClass() != kc ? 0 :
                ((Comparable)k).compareTo(x)); // 否则返回k.compareTo(x)
    }

    /**
     * 对于给定的目标容量,返回一个2的幂。(例如cap=32或者30,返回32)
     * 

这个方法给public HashMap(int initialCapacity, float loadFactor) 用. *

如果用户输入一个不为2的幂的数字,将它调整为一个是2的幂的数字,刚刚 > = cap */ static final int tableSizeFor(int cap) { int n = cap - 1; // 如果cap已经是2的幂, 又没有执行这个减1操作,则执行完后面的几条无符号右移操作之后,返回的capacity将是这个cap的2倍。 n |= n >>> 1; // 最高位为1,1xx | 01x = 11x 最高位的后一位变为1,包括最高位2位为1 n |= n >>> 2; // 11xxx | 0011x = 1111x 包括最高位4位为1 n |= n >>> 4; // 包括最高位8位为1 n |= n >>> 8; // 包括最高位16位为1 n |= n >>> 16; // 包括最高位32位为1 // 到这里保证n的最高位后面的所有位为1 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; // 最后n<0 ,返回1 // n=0,返回1 // n>0,返回n+1 111111 + 1 =100000 最后返回2的幂 }

字段 table,entrySet,size,modCount,threshold,loadFactor

    /* ---------------- Fields -------------- */

    /**
     * 哈希表,第一次使用时,初始化,根据需要调整大小。
     * 当分配空间时,长度永远是2的幂。
     * (在一些操作中,我们长度为0,来允许当前不需要的引导机制。
     * 注意:HashMap.TreeNode extends LinkedHashMap.Entry
     * LinkedHashMap.Entry extends HashMap.Node
     * 所以TreeNode是Node的子类
     */
    transient Node[] table;

    /**
     * 保存着缓存的entrySet().
     * 注意:AbstractMap的字段为了keySet() 和 values() 使用。
     * (AbstractMap有keySet和values字段,Hashmap有entrySet字段。)
     */
    transient Set> entrySet;

    /**
     * map中key-value映射的数量。
     */
    transient int size;

    /**
     * 这个Hashmap在结构上被改变的次数。
     * 结构上的改变是那些改变Hashmap中映射的数量,或者一个改变内部结构的方式(例如调整大小,rehash)
     * 这个字段让HashMap的集合视图上的迭代器快速失败。
     */
    transient int modCount;

    /**
     * 下一次调整大小时的size的值。(capacity * load factor).
     *
     * @serial
     */
    // (序列化时javadoc描述为true。此外,如果没有分配表数组,则此字段保留初始数组容量,或零表示
    int threshold;

    /**
     * 哈希表的负载因子。
     * 

capacity * load factor= size *

size/load factor=capacity *

size/capacity=load factor * @serial */ final float loadFactor;

构造函数 4个(重要)

    /**
     * 创建一个有着指定初始容量和负载因子的空的HashMap
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    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);
        //loadFactor>0,直接设置给loadFactor
        this.loadFactor = loadFactor;
        //  0<=initialCapacity<=MAXIMUM_CAPACITY=1<<30
        // 设置initialCapacity的一个2的幂(即大于等于initialCapacity的2的幂)
        // 再赋值给threshold,不初始化table!!!
        this.threshold = tableSizeFor(initialCapacity);
    }

    /**
     * 创建一个有着指定初始容量和默认负载因子(0.75)的空的HashMap
     *
     * @param  initialCapacity the initial capacity.
     * @throws IllegalArgumentException if the initial capacity is negative.
     */
    public HashMap(int initialCapacity) {
    	//使用上面的构造函数,loadFactor=DEFAULT_LOAD_FACTOR=0.75
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    /**
     * 创建一个有着默认初始容量(16)和默认负载因子(0.75)的空的HashMap
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
        // 只设置loadFactor,不设置threshold,threshold还是为0
    }

    /**
     * 创建一个与指定map相同映射的新的HashMap。
     * 这个HashMap创建,有默认的负载因子(0.75),有一个足够容纳指定map的映射的初始容量。
     *
     * @param   m the map whose mappings are to be placed in this map
     * @throws  NullPointerException if the specified map is null
     */
    public HashMap(Map m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        // 设置loadFactor,然后全部插入m的映射
        putMapEntries(m, false);
    }

查询方法 size,isEmpty,get,getNode(重要),containsKey,containsValue

    /**
     * 返回map中key-value对的数量。
     *
     * @return the number of key-value mappings in this map
     */
    public int size() {
        return size;
    }

    /**
     * 如果map不包含任何key-value对,返回true
     *
     * @return true if this map contains no key-value mappings
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 得到指定key映射的value,或者如果map不包含key对于的映射,返回null
     *
     * 

更正式地,如果map包含一个这样的映射,里面的key k 和value v是这样的 * {@code (key==null ? k==null :key.equals(k))} ,那么方法返回v。 * 否则,返回null。(里面最多一个这样的映射) * *

返回null,不一定表明map不包含这个key对应的映射。 * 也可能key对应的值为null。 * containsKey操作可以用于辨明这两种情况。 * * @see #put(Object, Object) */ public V get(Object key) { Node e; // 根据getNode方法得到节点e,再返回e的value return (e = getNode(hash(key), key)) == null ? null : e.value; } /** * 实现Map.get并且关联方法。 * * @param hash hash for key * @param key the key * @return the node, or null if none */ final Node getNode(int hash, Object key) { Node[] tab; Node first, e; int n; K k; // 把table赋值给tab,table的长度赋值给n if ((tab = table) != null && (n = tab.length) > 0 && // first是哈希表中key对应节点所处在的那个桶的头一个节点。 // 那个桶的index为 table.length-1 & hash (即获取hash的低位的x位,table.length = 2 ^ x) // hash是 key.hashcode ^ (hashcode >>> 16) 即高位16位不变,低位16位与高位16位进行亦或运算。 (first = tab[(n - 1) & hash]) != null) { // 先检查first.hash与hash是否相同 if (first.hash == hash && // 永远检查first节点 // 将first.key赋值给k,并检查k与key是否是同一个引用,或者equals相同 ((k = first.key) == key || (key != null && key.equals(k)))) // 两个都相同,返回first return first; // 到这里说明first不为对应节点,如果first.next不为null,则检查first后面的节点 // 将first.next赋值给e if ((e = first.next) != null) { if (first instanceof TreeNode) // 如果first是TreeNode,则返回TreeNode的getTreeNode方法 return ((TreeNode)first).getTreeNode(hash, key); do { // 这里,说明first是普通节点 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) // 检查e的hash与e的key是否对应 return e; // 根据链表 e = e.next 不断检查,直到next为null } while ((e = e.next) != null); } } return null; } /** * 如果map包含有着指定的key的映射,返回true。 * * @param key The key whose presence in this map is to be tested * @return true if this map contains a mapping for the specified * key. */ public boolean containsKey(Object key) { // 得到节点的节点,根据是否为null,判断是否有这个key // get是返回node的value,所以有可能返回null return getNode(hash(key), key) != null; }

    /**
     * 如果map包含有着一个或多个指定的value的映射,返回true。
     *
     * @param value value whose presence in this map is to be tested
     * @return true if this map maps one or more keys to the
     *         specified value
     */
    public boolean containsValue(Object value) {
        Node[] tab; V v;
        if ((tab = table) != null && size > 0) {
        	// 对tab进行循环
            for (int i = 0; i < tab.length; ++i) {
            	// 对tab[i]不断next进行迭代
                for (Node e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value ||
                        (value != null && value.equals(v)))
                    	// 找到value对应的,返回true
                        return true;
                }
            }
        }
        return false;
    }

放入操作  put,putVal(重要),resize(重要),treeifyBin,putAll,putMapEntries

    /**
     * 将指定的key与指定的value在这个map中关联(可选操作)。
     * 如果map之前包含了这个key的映射,旧的value被指定value替代。
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with key, or
     *         null if there was no mapping for key.
     *         (A null return can also indicate that the map
     *         previously associated null with key.)
     */
    public V put(K key, V value) {
    	// 调用putVal方法
        return putVal(hash(key), key, value, false, true);
    }

    /**
     * 实现Map.put并且关联方法。
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent 如果true,则不改变已经存在的value
     * @param evict 如果false,哈希表处于创建阶段。
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node[] tab; Node p; int n, i;
        // 把table赋值给tab,table的长度赋值给n
        if ((tab = table) == null || (n = tab.length) == 0)
        	// 如果tab为null或者长度为0,则调用resize方法
        	// 返回初始化后的节点数组,赋值给tab,同时table的长度赋值给n
            n = (tab = resize()).length;
        // 把哈希表中对应的桶赋值给p
        if ((p = tab[i = (n - 1) & hash]) == null)
        	//如果hash对应的桶为null,则新建一个节点,赋值给那个桶
            tab[i] = newNode(hash, key, value, null);
        else {
        	// 如果对应的桶不为null
            Node e; K k;
            // 下面的代码目的是找到在p这个桶下,hash和key对应的已经存在的那个节点,赋值给e
            if (p.hash == hash &&
            	// 把p的key赋值给k
                ((k = p.key) == key || (key != null && key.equals(k))))
            	// 如果p的hash和key正确,将p赋给e
                e = p;
            else if (p instanceof TreeNode)
            	// 如果p是TreeNode,调用putTreeVal方法,将返回值赋给e
                e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                	// 将p.next赋给e
                	// 如果e为null,说明链表到头,构造新节点,hash,key,value,然后设置给p.next,然后跳出
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        	// binCount为原来的数目-1,binCount+1为原来的数目
                        	// 如果binCount+1>=TREEIFY_THRESHOLD=8
                        	// 原来的数目>=8,加入后,有9个节点,则树化桶
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                    	// 如果e的数据正确,跳出
                        break;
                    // 将e赋给p,就是p=p.next
                    p = e;
                }
            }
            if (e != null) { // 这种情况不是新增节点,而是对已经存在节点进行修改
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

    /**
     * 初始化或者倍化表的大小(*2)。
     * 如果表为null,使用字段threshold作为初始容量目标,分配空间。
     * 否则,因为我们使用2的幂的扩展,每个桶的元素,要么待在同一个index的桶,要么index+新表中2的幂。
     * 比如110+1000=1110,就是加了2的幂
     *
     * @return the table
     */
    final Node[] resize() {
    	// 将现在的table赋值给oldTab
        Node[] oldTab = table;
        // 如果现在的table,oldCap=0,否则为table.length
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        // 将threshold赋值给oldThr
        int oldThr = threshold;
        int newCap, newThr = 0;
        // 下面的代码是得到新的容量和阀值,即newCap, newThr
        if (oldCap > 0) {
        	// 如果oldCap>0,说明是扩容(*2)的情况
            if (oldCap >= MAXIMUM_CAPACITY) {
            	// 如果oldCap超过限制,则设置threshold = Integer.MAX_VALUE,将现在的table直接返回
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            // 将oldCap << 1 赋值给newCap
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
            	// 如果nexCap=16,
            	// 将oldThr << 1 赋值给newThr
                newThr = oldThr << 1; // double threshold
        }
        // 到这里说明是哈希表新建的情况
        else if (oldThr > 0) // threshold字段保存了初始容量(如果设置了)
        	// 将oldThr 赋值给newCap
            newCap = oldThr;
        else {               // 没有指定初始容量,即threshold为0,则容量为默认值。
        	// 将16赋值给newCap
        	// 将12赋值给newThr
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }       
        if (newThr == 0) {
        	// 这里说明要么新建哈希表指定了初始容量,要么nexCap>MAXIMUM_CAPACITY , oldCap < 16
        	// 根据newCap和loadFactor重新设置threshold
            float ft = (float)newCap * loadFactor;
            // 如果nexCap>MAXIMUM_CAPACITY,则newThr=Integer.MAX_VALUE
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        // 将newThr赋值给threshold
        // 将new Node[newCap]赋值给newTab
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
            Node[] newTab = (Node[])new Node[newCap];
        // 将newTab赋值给table
        table = newTab;
        if (oldTab != null) {
        	// 如果oldTab != null,则是扩容状态,对旧表的数据向新表迁移
            for (int j = 0; j < oldCap; ++j) {
                Node e;
                // 对oldTab进行遍历,将oldTab[j]赋值给e
                if ((e = oldTab[j]) != null) {
                	// 如果e不为null,则迁移
                	// 将旧表清空,oldTab[j] = null
                    oldTab[j] = null;
                    if (e.next == null)
                    	// 如果只有一个节点,新的index为  e.hash & (newCap - 1)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                    	// 如果e是TreeNode,调用e的split方法进行重新分配
                        ((TreeNode)e).split(this, newTab, j, oldCap);
                    else { // 保持顺序
                        Node loHead = null, loTail = null;
                        Node hiHead = null, hiTail = null;
                        Node next;
                        do {
                        	// 将e.next赋值给next
                            next = e.next;
                            // oldCap=1000,newCap=10000
                            // 本来要放入新桶的hash & (newCap-1) = hash & 1111
                            // 现在hash & oldCap = hash & 1000
                            // 如果结果为0,hash为0xxx,说明 hash & 1111=hash & 0111,还是在原来的桶
                            // 如果结果不为0,hash为1xxx,
                            
                            if ((e.hash & oldCap) == 0) {
                            	//(e.hash & oldCap) == 0,说明还是在原来的桶
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                                // 在lo中,形成一个链表,第一个为head,接下来不断放在tail的next
                                // newTab[j] = loHead;
                            }
                            else {
                            	// 说明在另一个桶
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                             // 在hi中,形成一个链表,第一个为head,接下来不断放在tail的next
                             // newTab[j + oldCap] = hiHead;   
                            }
                        } while ((e = next) != null);
                        //设置完两个链表后,将两个head赋值给新表中两个桶
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

    /**
     * 将哈希表中根据给定hash得到的index里的桶里的全部节点替换,
     * 如果表太小,不提货,进行resize
     */
    final void treeifyBin(Node[] tab, int hash) {
        int n, index; Node e;
        // 将tab.length赋值给n
        // 如果tab为null或者tab.length < MIN_TREEIFY_CAPACITY=64,进行resize操作,不进行树化桶
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        // 将(n - 1) & hash赋值给index
        // 将tab中index的桶赋给e
        // 如果e不为null,进行树化
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode hd = null, tl = null;
            do {
            	// return new TreeNode<>(p.hash, p.key, p.value, next);
            	// 将一个有着e的hash,key,value,next为null的TreeNode赋值给p,
                TreeNode p = replacementTreeNode(e, null);
                if (tl == null)
                	// 如果尾节点tl为null,将p赋值给root节点hd
                    hd = p;
                else {
                	// 否则,设置p的prev,设置tl的next
                    p.prev = tl;
                    tl.next = p;
                }
                // 将p赋值给尾节点tl
                tl = p;
                // 不断e=e.next
            } while ((e = e.next) != null);
            // 将root节点hd赋值给tab[index]
            if ((tab[index] = hd) != null)
            	//转换为TreeNode节点后,进行树化
                hd.treeify(tab);
        }
    }

    /**
     * 复制指定map,所有的映射,到这个map。
     * 这个map和指定map都有的key,对应的映射会被替换。
     * 
     *
     * @param m mappings to be stored in this map
     * @throws NullPointerException if the specified map is null
     */
    public void putAll(Map m) {
        putMapEntries(m, true);
    }
    /**
     * 实现Map.putAll方法和Map的构造器
     *
     * @param m the map
     * @param evict false when initially constructing this map, else
     * true (relayed to method afterNodeInsertion).
     */
    final void putMapEntries(Map m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
            	//此时,map为空
            	// ft为map放入指定map需要的threshold
                float ft = ((float)s / loadFactor) + 1.0F;
                // t为ft与MAXIMUM_CAPACITY的较小的数
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                	// 设置threshold为大于等于t的2的幂
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                // 逐个调用putVal方法进入,注意:参数为false和evict
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

HashMap的构造方法,get,put总结

HashMap(int initialCapacity, float loadFactor) 赋值loadFactor,设置threshold =tableSizeFor(initialCapacity),即大于等于initialCapacity的2的幂,再赋值给threshold,不初始化table。

HashMap(int initialCapacity),调用this(initialCapacity, DEFAULT_LOAD_FACTOR)。

HashMap(),只设置loadFactor=默认值0.75,不设置threshold,threshold还是为0。

hash(Object key)方法,null 为 0,否则结果为 hashcode ^ (hashcode >>> 16),即高位16位不变,低位16位与高位16位进行亦或运算。

 

get方法,调用getNode(hash(key), key),在table的桶的index为 table.length-1 & hash处进行查找。首先检查tab[index]节点,如果不是,则,如果是树桶,返回((TreeNode)first).getTreeNode(hash, key)。否则,沿着链表 e = e.next 不断检查(先判断
hash,再判断key是否相等),直到next为null 。

getTreeNode方法,对这个节点调用root方法,得到这个节点的root,调用find,从根里去找h和k。

find方法,使用给定的hash和key,从root p(就是TreeNode自己)开始找节点,先比较hash,如果hash相同,比较key,如果key不同,然后得到key对应的comparableClass,进行比较,如果比较结果相同,或者不能比较,对右孩子调用find方法,如果没找到,让左孩子进入查找的循环。

 

put方法,调用putVal方法,其中,先调用resize()方法,在table的桶的index为 table.length-1 &hash处,首先检查tab[index]节点,如果为null,放置新节点。如果是TreeNode,调用putTreeVal方法,将返回值赋给e。否则,沿着链表进行寻找,如果找到,修改节点的value,如果到末尾没有,在末尾处新增一个节点。如果原来的数目>=8,加入后,有9个节点,则树化桶,调用treeifyBin。如果新增了节点,新的size>threshold,调用resize方法。

resize方法,如果table为null,如果threshold>0,newCap=threshold,newThr=newCap*loadfactor。否则,将16赋值给newCap,将12赋值给newThr。然后建立大小为newCap的Node数组。如果table不为null,如果oldCap >=MAXIMUM_CAPACITY,threshold = Integer.MAX_VALUE,返回旧的table。否则newCap=oldCap<<1,即乘以2,newThr=newCap*loadfactor。然后建立大小为newCap的Node数组。

迁移旧数据,对oldTab的每个桶进行遍历,如果只有一个节点,newTab[e.hash & (newCap - 1)] = e。如果e是TreeNode,调用e的split方法进行重新分配。如果有多个节点,建立两个链表,(e.hash &oldCap) == 0,即hash&1000=0,hash&1111=hash&111,说明还是在原来的桶,放在loTail处,否则放在hiTail处。然后newTab[j] = loHead,newTab[j + oldCap] = hiHead。

treeifyBin方法内,如果tab为null或者tab.length < MIN_TREEIFY_CAPACITY=64,进行resize操作,不进行树化桶,否则,进行树化操作。

split方法内,将一个树桶的节点分割为低位和高位的树桶,或者如果新的桶的节点数<=6,tab[index]为反树化结果。
 

删除操作 remove,removeNode,clear

    /**
     * 将map中key对应的映射移除,如果映射存在
     *
     * @param  key key whose mapping is to be removed from the map
     * @return the previous value associated with key, or
     *         null if there was no mapping for key.
     *         (A null return can also indicate that the map
     *         previously associated null with key.)
     */
    public V remove(Object key) {
        Node e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }

    /**
     * 实现remove和相关的方法
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to match if matchValue, else ignored
     * @param matchValue if true only remove if value is equal
     * @param movable if false do not move other nodes while removing
     * @return the node, or null if none
     */
    final Node removeNode(int hash, Object key, Object value,
                               boolean matchValue, boolean movable) {
        Node[] tab; Node p; int n, index;
        // 将table赋值给tab,tab.length赋值给n
        //(n - 1) & hash赋值给index , tab[index]赋值给p
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {
            Node node = null, e; K k; V v;
            // 将p的key赋值给k
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
            	// 如果p的hash和key对应,将p赋值给node
                node = p;
            // 不对应的话,将p.next赋值给e,如果e不为null
            else if ((e = p.next) != null) {
                if (p instanceof TreeNode)
                	// 如果p是TreeNode,将p.getTreeNode(hash, key)赋值给node
                    node = ((TreeNode)p).getTreeNode(hash, key);
                else {
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                        	// 如果e不为null,p也不是TreeNode,不断遍历链表,找到对应的节点e,赋值给node
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
            	// 如果node不为null,并根据matchValue与node的value的对应关系
                if (node instanceof TreeNode)
                	// 如果node是TreeNode,调用node的removeTreeNode(this, tab, movable)
                    ((TreeNode)node).removeTreeNode(this, tab, movable);
                else if (node == p)
                	// 如果node是p,即node是头结点,tab[index] = node.next
                    tab[index] = node.next;
                else
                	// 否则p为node的上一个节点,p.next = node.next
                    p.next = node.next;
                ++modCount;
                --size;
                // 调用afterNodeRemoval(node)
                afterNodeRemoval(node);
                return node;
            }
        }
        return null;
    }

    /**
     * 删除map中所有的映射。
     * 调用返回后,map为空。
     */
    public void clear() {
        Node[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
        	// size设为0,tab的每个桶都设为null
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }

三个视图 keySet,values,entrySet

    /**
     * 返回这个map中包含的key的set视图。
     * set由map支持,所以对map的改变会反映到set中,反之亦然。
     * 如果map被修改,同时set的迭代正在进行(除了通过Iterator自己的remove操作),迭代的结果未知。
     * set支持元素的删除,会导致map中对应的映射被删除,通过Iterator.remove,Set.remove,
     * removeAll,retainAll,clear操作。
     * set不支持add或者addAll操作。
     *
     * @return a set view of the keys contained in this map
     */
    public Set keySet() {
    	// 单例模式,没有则创建一个keySet,一个hashMap一个keySet
        Set ks = keySet;
        if (ks == null) {
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

    final class KeySet extends AbstractSet {
    	// size,clear,contains,remove,分别调用hashmap的size,clear,containsKey,removeNode方法
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        // 迭代器返回KeyIterator
        public final Iterator 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;
        }
        // 分割器返回KeySpliterator
        public final Spliterator spliterator() {
            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer action) {
            Node[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                int mc = modCount;
                // 对HashMap的表tab,的每个桶,不断e=e.next,进行遍历
                for (int i = 0; i < tab.length; ++i) {
                    for (Node e = tab[i]; e != null; e = e.next)
                        action.accept(e.key);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }

    /**
     * 返回这个map中包含的value的collection视图。
     * collection由map支持,所以对map的改变会反映到collection中,反之亦然。
     * 如果map被修改,同时collection的迭代正在进行(除了通过Iterator自己的remove操作),迭代的结果未知。
     * collection支持元素的删除,会导致map中对应的映射被删除,通过Iterator.remove,collection.remove,
     * removeAll,retainAll,clear操作。
     * collection不支持add或者addAll操作。
     *
     * @return a view of the values contained in this map
     */
    public Collection values() {
        Collection vs = values;
        if (vs == null) {
            vs = new Values();
            values = vs;
        }
        return vs;
    }
    
    // 如同keySet
    final class Values extends AbstractCollection {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator iterator()     { return new ValueIterator(); }
        public final boolean contains(Object o) { return containsValue(o); }
        public final Spliterator spliterator() {
            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer action) {
            Node[] 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 e = tab[i]; e != null; e = e.next)
                        action.accept(e.value);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }

    /**
     * 返回这个map中包含的映射的set视图。
     * set由map支持,所以对map的改变会反映到set中,反之亦然。
     * 如果map被修改,同时set的迭代正在进行(除了通过Iterator自己的remove操作),迭代的结果未知。
     * set支持元素的删除,会导致map中对应的映射被删除,通过Iterator.remove,Set.remove,
     * removeAll,retainAll,clear操作。
     * set不支持add或者addAll操作。
     *
     * @return a set view of the mappings contained in this map
     */
    public Set> entrySet() {
        Set> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }

    final class EntrySet extends AbstractSet> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator> 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();
            // 先根据key,getNode方法得到Node,再判断value是否相同
            Node 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();
                // 删除key和value都对应的节点
                return removeNode(hash(key), key, value, true, true) != null;
            }
            return false;
        }
        public final Spliterator> spliterator() {
            return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer> action) {
            Node[] 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 e = tab[i]; e != null; e = e.next)
                        action.accept(e);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }

一堆覆盖了JDK8的Map的default方法 getOrDefault,putIfAbsent,remove,replace两个,computeXXX3个,merge,forEach,replaceAll

    // 覆盖了JDK8的Map,附加的方法(原来都是default的)

    @Override
    public V getOrDefault(Object key, V defaultValue) {
        Node e;
        // getNode赋值给e,返回null时,返回defaultValue,否则返回e.value
        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
    }

    @Override
    public V putIfAbsent(K key, V value) {
    	// put时是  return putVal(hash(key), key, value, false, true);
    	// 第三个参数  onlyIfAbsent 如果true,则不改变已经存在的value
        return putVal(hash(key), key, value, true, true);
    }

    @Override
    public boolean remove(Object key, Object value) {
    	// remove(key) 方法是   removeNode(hash(key), key, null, false, true))
    	// 第三个参数 value the value to match if matchValue, else ignored
        // 第四个参数 matchValue if true only remove if value is equal
        return removeNode(hash(key), key, value, true, true) != null;
    }

    @Override
    public boolean replace(K key, V oldValue, V newValue) {
        Node e; V v;
        if ((e = getNode(hash(key), key)) != null &&
            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
        	// 如果getNode的结果赋值给e,e不为null,并且e的value与oldValue相同
        	// newValue赋值给e.value
            e.value = newValue;
            afterNodeAccess(e);
            return true;
        }
        return false;
    }

    @Override
    public V replace(K key, V value) {
        Node e;
        if ((e = getNode(hash(key), key)) != null) {
        	// 如上,不判断oldValue
            V oldValue = e.value;
            e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
        return null;
    }

    @Override
    public V computeIfAbsent(K key,
                             Function mappingFunction) {
        if (mappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node[] tab; Node first; int n, i;
        int binCount = 0;
        TreeNode t = null;
        Node old = null;
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        // 先得到hash对应的桶,然后类似于getNode,得到key对应的那个节点,赋值给old,
        if ((first = tab[i = (n - 1) & hash]) != null) {
            if (first instanceof TreeNode)
            	// 如果first是TreeNode,将key对应的节点赋值给t,也赋值给old
                old = (t = (TreeNode)first).getTreeNode(hash, key);
            else {
                Node 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);
            }
            V oldValue;
            // 如果old和oldValue不为null,直接返回
            if (old != null && (oldValue = old.value) != null) {
                afterNodeAccess(old);
                return oldValue;
            }
        }
        // 使用给出的function算出v
        V v = mappingFunction.apply(key);
        // 如果为null,直接返回null
        if (v == null) {
            return null;
            // 如果old不为null,即old对应的key存在,但是value原来是null,设置节点value为v
        } else if (old != null) {
            old.value = v;
            afterNodeAccess(old);
            return v;
        }
        else if (t != null)
        	// 此时桶为树桶,调用t的putTreeVal
            t.putTreeVal(this, tab, hash, key, v);
        else {
        	// 普通的桶,在桶处新建一个,然后新节点的next为原来的first
            tab[i] = newNode(hash, key, v, first);
            if (binCount >= TREEIFY_THRESHOLD - 1)
                treeifyBin(tab, hash);
        }
        ++modCount;
        ++size;
        afterNodeInsertion(true);
        return v;
    }

    public V computeIfPresent(K key,
                              BiFunction remappingFunction) {
        if (remappingFunction == null)
            throw new NullPointerException();
        Node e; V oldValue;
        int hash = hash(key);
        // 先getNode,然后如果key对应的value存在,而且非null
        if ((e = getNode(hash, key)) != null &&
            (oldValue = e.value) != null) {
        	// 计算出v,如果v不为null,设置e的value
            V v = remappingFunction.apply(key, oldValue);
            if (v != null) {
                e.value = v;
                afterNodeAccess(e);
                return v;
            }
            else
            	// 如果function返回null,映射被删除
                removeNode(hash, key, null, false, true);
        }
        return null;
    }

    @Override
    public V compute(K key,
                     BiFunction remappingFunction) {
        if (remappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node[] tab; Node first; int n, i;
        int binCount = 0;
        TreeNode t = null;
        Node old = null;
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((first = tab[i = (n - 1) & hash]) != null) {
            if (first instanceof TreeNode)
                old = (t = (TreeNode)first).getTreeNode(hash, key);
            else {
                Node 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得到对应的old,再设置oldValue
        V oldValue = (old == null) ? null : old.value;
        // 根据key和oldValue计算出v
        V v = remappingFunction.apply(key, oldValue);
        if (old != null) {
            if (v != null) {
            	// 如果function返回不为null,重新设置old的value。
                old.value = v;
                afterNodeAccess(old);
            }
            else
            	// 如果function返回null,移除这个映射(如果一开始就没有,就还是没有)。
                removeNode(hash, key, null, false, true);
        }
        // 如果没有原来节点,加入key,v键值对
        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;
    }

    @Override
    public V merge(K key, V value,
                   BiFunction remappingFunction) {
        if (value == null)
            throw new NullPointerException();
        if (remappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node[] tab; Node first; int n, i;
        int binCount = 0;
        TreeNode t = null;
        Node old = null;
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((first = tab[i = (n - 1) & hash]) != null) {
            if (first instanceof TreeNode)
                old = (t = (TreeNode)first).getTreeNode(hash, key);
            else {
                Node 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);
            }
        }
        if (old != null) {
            V v;
            if (old.value != null)
            	// 新的value为function根据oldValue和value得到的值
                v = remappingFunction.apply(old.value, value);
            else
                v = value;
            if (v != null) {
                old.value = v;
                afterNodeAccess(old);
            }
            else
                removeNode(hash, key, null, false, true);
            return v;
        }
        // 如果没有old,插入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;
    }

    @Override
    public void forEach(BiConsumer action) {
        Node[] 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 e = tab[i]; e != null; e = e.next)
                	// 对每个桶,每个桶内的节点,不断e = e.next,进行遍历
                    action.accept(e.key, e.value);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

    @Override
    public void replaceAll(BiFunction function) {
        Node[] 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 e = tab[i]; e != null; e = e.next) {
                	// value为function根据原来的key和value生成的新value
                    e.value = function.apply(e.key, e.value);
                }
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

clone,writeObject,readObject

    /* ------------------------------------------------------------ */
    // Cloning and serialization

    /**
     * 返回HashMap实例的浅复制:keys和values它们自己没有被复制。
     *
     * @return a shallow copy of this map
     */
    @SuppressWarnings("unchecked")
    @Override
    public Object clone() {
        HashMap result;
        try {
            result = (HashMap)super.clone();
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
        // 设置各个字段变成初始的默认值(null或者0)。
        result.reinitialize();
        // 把自己所有的entry加入result
        result.putMapEntries(this, false);
        return result;
    }

    // 下面两个方法在序列化HashSet时被使用
    final float loadFactor() { return loadFactor; }
    final int capacity() {
        return (table != null) ? table.length :
            (threshold > 0) ? threshold :
            DEFAULT_INITIAL_CAPACITY;
    }

    /**
     * 保存HashMap的状态为一个流,序列化
     *
     * @serialData The capacity of the HashMap (the length of the
     *             bucket array) is emitted (int), followed by the
     *             size (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 {
        int buckets = capacity();
        // 写出threshold, loadfactor,和其他隐藏的元素
        s.defaultWriteObject();
        // 写桶的大小和size
        s.writeInt(buckets);
        s.writeInt(size);
        // 安装桶的顺序,桶内不断next的顺序,依次写入key和value
        internalWriteEntries(s);
    }

    /**
     * 从一个流,重组HashMap实例,反序列化
     */
    private void readObject(java.io.ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        // 读入threshold, loadfactor,和其他隐藏的元素
        s.defaultReadObject();
        // 设置各个字段变成初始的默认值(null或者0)。
        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) { // (如果mappings为0,使用默认的,即啥都不干)
        	// 计算table的大小,当给定的负载因子大小在0.25-4.0之间,使用它来计算
        	// lf为计算后的负载因子
            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
            // fc为映射数量和负载因子计算后的capacity
            float fc = (float)mappings / lf + 1.0f;
            // 根据capacity的上下限和tableSizeFor后的fc,得到cap,为table的大小
            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                       DEFAULT_INITIAL_CAPACITY :
                       (fc >= MAXIMUM_CAPACITY) ?
                       MAXIMUM_CAPACITY :
                       tableSizeFor((int)fc));
            // 根据更新后的cap和lf计算出ft,然后根据上下限,和ft,计算出threshold
            float ft = (float)cap * lf;
            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                         (int)ft : Integer.MAX_VALUE);
            @SuppressWarnings({"rawtypes","unchecked"})
                Node[] tab = (Node[])new Node[cap];
            table = tab;

            // 读入key和value,将映射放入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);
            }
        }
    }
    // 仅仅被writerObject调用,保证兼容的顺序。
    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
        Node[] tab;
        if (size > 0 && (tab = table) != null) {
            for (int i = 0; i < tab.length; ++i) {
                for (Node e = tab[i]; e != null; e = e.next) {
                	// 安装桶的顺序,桶内不断next的顺序,依次写入key和value
                    s.writeObject(e.key);
                    s.writeObject(e.value);
                }
            }
        }
    }

 

迭代器 HashIterator,KeyIterator,ValueIterator,EntryIterator

    // iterators

    abstract class HashIterator {
        Node next;        // 下一个返回的entry
        Node current;     // 当前的entry
        int expectedModCount;  // 为了快速失败机制
        int index;             // 下一个桶的index

        HashIterator() {
            expectedModCount = modCount; // 创建时记录modCount
            Node[] t = table;
            current = next = null; // current和next为null
            index = 0; // index初始为0
            if (t != null && size > 0) { // 不断递进index,直到t[index]不为null,将t[index]赋值给next
            	// 循环完后,index是next对应桶的下一个桶的下标
                do {} while (index < t.length && (next = t[index++]) == null);
            }
        }

        public final boolean hasNext() {
            return next != null;
        }

        // KeyIterator等三个Iterator继承这个类,它们三个的next方法都调用这个方法,得到nextNode().key/value
        final Node nextNode() {
            Node[] t;
            Node e = next; 
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            // 先将e赋值给current,再将current.next赋值给next
            // 如果next不为null,直接结束
            // next为null,并且t不为null,不断递进index,直到t[index]不为null,将t[index]赋值给next
            if ((next = (current = e).next) == null && (t = table) != null) {
                do {} while (index < t.length && (next = t[index++]) == null);
            }
            // 返回调用nextNode时的next
            return e;
        }

        public final void remove() {
            Node p = current;
            if (p == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            // 设置current指针位null
            current = null;
            K key = p.key;
            // 删除key为current的key的节点
            removeNode(hash(key), key, null, false, false);
            expectedModCount = modCount;
        }
    }

    // 三者的hasNext,remove方法都相同
    // 只有next方法不一样,分别返回key,value,entry
    final class KeyIterator extends HashIterator
        implements Iterator {
        public final K next() { return nextNode().key; }
    }

    final class ValueIterator extends HashIterator
        implements Iterator {
        public final V next() { return nextNode().value; }
    }

    final class EntryIterator extends HashIterator
        implements Iterator> {
        public final Map.Entry next() { return nextNode(); }
    }

分割器 4个,如迭代器

    // spliterators

    static class HashMapSpliterator {
        final HashMap map;
        Node current;          // 当前节点,就是下一个处理的节点
        int index;                  // current index, modified on advance/split 当前index,在advance/split时修改
        int fence;                  // one past last index 最后一次的index
        int est;                    // size estimate 预计大小
        int expectedModCount;       // for comodification checks

        HashMapSpliterator(HashMap m, int origin,
                           int fence, int est,
                           int expectedModCount) {
        	// return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
        	// super(m, origin, fence, est, expectedModCount);
            this.map = m; // map为自己
            this.index = origin; // 初始为0
            this.fence = fence; // 初始为-1
            this.est = est; // 初始为0
            this.expectedModCount = expectedModCount; // 初始为0
        }

        final int getFence() { // 第一次使用时,初始化fence和size
            int hi;
            // fence没有初始化前位-1
            // 将fence赋值给hi
            if ((hi = fence) < 0) {
            	// 如果hi小于0
                HashMap m = map;
                // 设置est和modCount为map里的值
                est = m.size;
                expectedModCount = m.modCount;
                Node[] tab = m.table;
                // fence设置为tab的length
                hi = fence = (tab == null) ? 0 : tab.length;
            }
            return hi;
        }

        public final long estimateSize() {
        	// 强制初始化,然后返回est,一开始为map的size
            getFence(); // force init
            return (long) est;
        }
    }

    static final class KeySpliterator
        extends HashMapSpliterator
        implements Spliterator {
        KeySpliterator(HashMap m, int origin, int fence, int est,
                       int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        public KeySpliterator trySplit() {
        	// fence赋值给hi,index赋值给lo,mid为中间值        	
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
                // 如果lo>=mid(数目太少了)或者current不为null(指针在一个桶的中间,不能分割),时,返回null
                // 新的spliterator范围为[lo(index),mid),大小为est/2
                // 自己的范围为[index(mid),fence),大小为est/2
            return (lo >= mid || current != null) ? null :
                new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
                                        expectedModCount);
        }

        public void forEachRemaining(Consumer action) {
            int i, hi, mc;
            if (action == null)
                throw new NullPointerException();
            HashMap m = map;
            Node[] 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)) {
            	// 从current开始循环
                Node p = current;
                current = null;
                do {
                	// 如果为null,到下一个桶
                	// 不为null,处理p的key,然后到p.next
                    if (p == null)
                        p = tab[i++];
                    else {
                        action.accept(p.key);
                        p = p.next;
                    }
                } while (p != null || i < hi); // 直到i为hi,即fence结束
                if (m.modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }

        public boolean tryAdvance(Consumer action) {
            int hi;
            if (action == null)
                throw new NullPointerException();
            Node[] tab = map.table;
            // 如果tab.length= (hi = getFence()) && index >= 0) {
            	// 如果current不为null或者index
        extends HashMapSpliterator
        implements Spliterator {
        ValueSpliterator(HashMap m, int origin, int fence, int est,
                         int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        public ValueSpliterator 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 action) {
            int i, hi, mc;
            if (action == null)
                throw new NullPointerException();
            HashMap m = map;
            Node[] 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 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();
            }
        }

        public boolean tryAdvance(Consumer action) {
            int hi;
            if (action == null)
                throw new NullPointerException();
            Node[] 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;
        }

        public int characteristics() {
            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
        }
    }

    static final class EntrySpliterator
        extends HashMapSpliterator
        implements Spliterator> {
        EntrySpliterator(HashMap m, int origin, int fence, int est,
                         int expectedModCount) {
            super(m, origin, fence, est, expectedModCount);
        }

        public EntrySpliterator 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> action) {
            int i, hi, mc;
            if (action == null)
                throw new NullPointerException();
            HashMap m = map;
            Node[] 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 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> action) {
            int hi;
            if (action == null)
                throw new NullPointerException();
            Node[] 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 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覆盖的方法   newNode2个(普通和树节点),replaceNode2个(普通和树节点),reinitialize,afterNodeXXX3个

    // LinkedHashMap 支持


    /*
     * 下面的protected方法(包内的方法),被用来被LinkedHashMap覆盖,但不会被其他子类覆盖。
     * 几乎所有的其他内部方法也是protected的方法,但被声明是final的,能被LinkedHashMap,视图类,HashSet使用。
     */

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

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

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

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

    /**
     * 设置各个字段变成初始的默认值(null或者0)。被clone和readObject方法调用。
     */
    void reinitialize() {
        table = null;
        entrySet = null;
        keySet = null;
        values = null;
        modCount = 0;
        threshold = 0;
        size = 0;
    }

    // 允许LinkedHashMap执行动作后的回调
    void afterNodeAccess(Node p) { }
    void afterNodeInsertion(boolean evict) { }
    void afterNodeRemoval(Node p) { }

树节点 TreeNode

    // 树桶

    /**
     * 对于树桶的entry。
     * 继承了LinkedHashMap.Entry,而LinkedHashMap.Entry extends HashMap.Node 。
     * 所以能用来被hashmap和LinkedHashMap使用,当做他们各自的通用的桶。
     */
    static final class TreeNode extends LinkedHashMap.Entry {
    	// node有 key,value, hash,next
    	// linkedlist的entry,增加了before,after
    	// TreeNode增加了 parent,left,right,prev,red
    	
        TreeNode parent;  // 红黑树的连接
        TreeNode left;
        TreeNode right;
        TreeNode prev;    // 在删除时,删除next时需要
        boolean red; // 默认为false
        TreeNode(int hash, K key, V val, Node next) {
            super(hash, key, val, next);
        }

        /**
         * 返回包含这个节点的树的根节点
         */
        final TreeNode root() {
            for (TreeNode r = this, p;;) {
            	// 不断parent,直到parent为null
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }

        /**
         * 保证给定的root是它的桶的第一个节点。
         */
        static  void moveRootToFront(Node[] tab, TreeNode root) {
            int n;
            // 将tab.length赋值给n
            if (root != null && tab != null && (n = tab.length) > 0) {
            	// 将(n - 1) & root.hash赋值给index,即root所处的桶的index
                int index = (n - 1) & root.hash;
                // 将tab[index]赋值给first
                TreeNode first = (TreeNode)tab[index];
                // 如果first和root不同
                if (root != first) {
                    Node rn;
                    // 将root赋值给tab[index] (原来是first)
                    tab[index] = root;
                    // 将root.prev赋值给rp
                    TreeNode rp = root.prev;
                    // 将root.next赋值给rn
                    // 如果rn不为null,将rp(root.prev)赋值给rn(root.next).prev
                    if ((rn = root.next) != null)
                        ((TreeNode)rn).prev = rp;
                    // 如果rp(root.prev)不为null,将rn(root.next)赋值给rp(root.prev).next
                    if (rp != null)
                        rp.next = rn;
                    // 如果first(tab[index])不为null,将root赋值给first(tab[index]).prev
                    if (first != null)
                        first.prev = root;
                    // 将first赋值给root.next,null赋值给root.prev
                    root.next = first;
                    root.prev = null;
                    // 即原来  tab[i]:   first             某个位置:  root.prev root  root.next
                    // 现在      tab[i]:   root  first       某个位置: root.prev  root.next
                }
                // 校验root
                assert checkInvariants(root);
            }
        }

        /**
         * 使用给定的hash和key,从root p(就是TreeNode自己)开始找节点。
         * kc参数在第一次使用比较键时缓存comparableClassFor(key)。
         * 先比较hash,如果hash相同,比较key,如果key不同,然后得到key对应的comparableClass,进行比较,
         * 如果比较结果相同,或者不能比较,对右孩子和左孩子依次调用find方法
         * (相当于对红黑树的下一层进行遍历,如果hash都相同,key都不能比较或者比较结果相同,相当于对整个红黑树遍历)
         */
        final TreeNode find(int h, Object k, Class kc) {
        	// 把自己赋值给p
            TreeNode p = this;
            // 从p开始,不断循环向下,找到对应节点
            do {
                int ph, dir; K pk;
                // p的左节点赋值给pl,右节点赋值给pr
                TreeNode pl = p.left, pr = p.right, q;
                // 将p的hash赋值给ph
                // 根据ph与h的大小,如果不同,将pl或者pr赋值给p
                if ((ph = p.hash) > h)
                    p = pl;
                else if (ph < h)
                    p = pr;
                // 如果hash相同,将p的key赋值给pk
                // 如果pk与k相同,返回p
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                // 如果pk与k不同,pl为null,pr赋值给p
                else if (pl == null)
                    p = pr;
                // 如果pk与k不同,pl不为null,pr为null,pl赋值给p
                else if (pr == null)
                    p = pl;
                // 如果pk与k不同,pl和pr不为null
                // 先根据kc或者k得到比较的类
                // 根据k与pk的比较关系,将pl或者pr赋值给p
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                // 如果k是不能比较的,或者p与pk比较结果相同
                // 对pr调用find,返回结果q
                // 如果在pr那里没找到,pl赋值给p
                else if ((q = pr.find(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
            return null;
        }

        /**
         * 对this的root节点,调用find方法,返回对应的节点。
         */
        final TreeNode getTreeNode(int h, Object k) {
        	// 对这个节点调用root方法,得到这个节点的root,调用find,从根里去找h和k
            return ((parent != null) ? root() : this).find(h, k, null);
        }

        /**
         * 当hashcode相同,但是不可比较时,用于排序插入的断开连接功能。
         * 我们不需要一个总顺序,只需要一个一致的插入规则来在重新平衡之间保持等价。断开连接比必要的更能简化测试。
         * 先比较null,再比较className,最后比较Object类默认的hashcode.
         */
        static int tieBreakOrder(Object a, Object b) {
            int d;
            // 如果a或者b为null,直接返回0
            if (a == null || b == null ||
            	// 返回a的class与b的class名字的比较结果		
                (d = a.getClass().getName().
                 compareTo(b.getClass().getName())) == 0)
            	// 如果类的名字的比较结果相同
            	// 比较a与b的Object类默认的hashcode方法比较的结果,返回-1或1
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                     -1 : 1);
            return d;
        }

        /**
         * 形成,与这个节点连接的一堆节点,构造成,的树,
         * 
         * @return root of tree
         */
        final void treeify(Node[] tab) {
            TreeNode root = null;
            // 将自己赋值给x
            // 对x进行循环,不断x=x.next,将每个next添加到树中
            for (TreeNode x = this, next; x != null; x = next) {
            	// 将x.next赋值给next
                next = (TreeNode)x.next;
                // 将null赋值给x的left与right
                x.left = x.right = null;
                if (root == null) {
                	//如果root为null
                	// null设置给x的parent,false设置给x的red(为黑)
                	// x设置给root
                    x.parent = null;
                    x.red = false;
                    root = x;
                }
                else {
                	// root不为null
                	// x的key赋值给k,x的hash赋值给h
                    K k = x.key;
                    int h = x.hash;
                    Class kc = null;
                    // root赋值给p
                    for (TreeNode p = root;;) {
                        int dir, ph;
                        // p的key赋值给pk
                        K pk = p.key;
                        // dir为p与x的hash与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);
                        // p赋值给xp
                        TreeNode xp = p;
                        // 根据dir,将p.left或者right赋值给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);
        }

        /**
         * 返回一个不是TreeNode的节点,这个节点连着的节点代替了之前的TreeNode
         */
        final Node untreeify(HashMap map) {
            Node hd = null, tl = null;
            for (Node q = this; q != null; q = q.next) {
            	// return new Node<>(p.hash, p.key, p.value, next);
            	// 将q转换为普通的节点,赋值给p
                Node p = map.replacementNode(q, null);
                // tl为队尾,hd为队头
                if (tl == null) 
                	// 设置队头hd为p
                    hd = p;
                else
                	// 不断队尾tl.next为p
                    tl.next = p;
                tl = p;
            }
            // 返回队头hd
            return hd;
        }

        /**
         * 树版本的putVal。
         * 会在树中插入一个新节点,或者将原有节点返回,在putVal里面对它的value进行修改
         */
        final TreeNode putTreeVal(HashMap map, Node[] tab,
                                       int h, K k, V v) {
            Class kc = null;
            boolean searched = false;
            
            // p = tab[i = (n - 1) & hash]
            // ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
            // p是这个hash对应tab里的桶,也就是自己this
            
            // root为自己这个节点的root节点
            TreeNode root = (parent != null) ? root() : this;
            // 将root赋值给p
            // 下面for的大循环的目的是,从root开始,根据hash和key,不断向下,遍历孩子,
            // 直到找到对应节点,或者对应节点没有,插入节点并维持红黑树平衡
            for (TreeNode p = root;;) {
                int dir, ph; K pk;
                
                // 下面的那个大if,是为了得到dir,确定下次迭代时,p=p.left/right
                // 大if中,如果hash和key相同,直接返回p
                // 如果hash相同,key无法比较,调用find方法,如果找到,返回q
                
                // 将p的hash赋值给ph
                if ((ph = p.hash) > h)
                    dir = -1;
                else if (ph < h)
                    dir = 1;
                
                // 到这里ph与h相同
                // 将p的key赋值给pk
                // 如果找到key和hash对应的节点p,将p返回
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                // 如果hash相同,key不同
                else if ((kc == null &&
                          (kc = comparableClassFor(k)) == null) ||
                		 // dir为k与pk比较的结果
                         (dir = compareComparables(kc, k, pk)) == 0) {
                	
                	// 如果比较结果为0
                    if (!searched) {
                        TreeNode q, ch;
                        // 注意:由于searched的关系 直接调用find方法只会有一次!
                        searched = true;
                        // 对left和right调用find方法,如果找到了,返回对应节点
                        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;
                    }
                    // 如果hash相同,key不同,比较结果为0,find没找到,调用tieBreakOrder赋值给dir
                    // 即对两者的className和默认的hashcode进行依次比较
                    dir = tieBreakOrder(k, pk);
                }
                
                //上面的那个不断if else的语句结束,已经找到了节点或者得到了dir

                // p赋值给xp
                TreeNode xp = p;
                // 根据dir,p=p.left/right
                // 但是如果赋值后p为null,代表没有找到对应节点,新增一个节点,并维持平衡
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                	// xp.next赋值给xpn
                    Node xpn = xp.next;
                    //  return new TreeNode<>(hash, key, value, next);
                    // 根据hash,key,value,xpn新建一个TreeNode给x
                    TreeNode x = map.newTreeNode(h, k, v, xpn);
                    // 根据dir,将xp(原来的p).left/right赋值给x
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    // 设置xp.next为x
                    xp.next = x;
                    // 设置x.parent和x.prev为xp
                    x.parent = x.prev = xp;
                    // 如果xpn不为null,设置xpn.prev=x
                    if (xpn != null)
                        ((TreeNode)xpn).prev = x;
                    // 先设置孩子关系,xp.left/right = x , x.parent = xp
                    // 然后设置双向链表的前后关系
                    // 原来 xp   xpn
                    // 现在 xp  x  xpn
                    // xp为x的父节点
                    
                    // 先维持插入x后的平衡
                    // 然后将平衡后的红黑树的新的root节点放到tab的最开始
                    moveRootToFront(tab, balanceInsertion(root, x));
                    return null;
                }
            }
        }

        /**
         * 删除给定的节点(就是this),那个节点必须在这次调用前存在。
         * 这比典型的红黑树删除节点更加混乱,因为我们因为我们不能使用由“next”指针固定的叶子后续来交换内部节点的内容,
         * 而“next”指针在遍历过程中是可独立访问的。
         * 所以,替代地,我们交换树的连接顺序。
         * 如果当前的树看上去有着过少的节点,桶被转换为普通的桶。(触发条件是2-6个节点间,取决于树的结构)
         */
        final void removeTreeNode(HashMap map, Node[] tab,
                                  boolean movable) {
            int n;
            // 如果tab为null或者长度为0,则直接返回
            // tab.length赋值给n
            if (tab == null || (n = tab.length) == 0)
                return;
            // index为hash对应的桶的index
            int index = (n - 1) & hash;
            // tab[index]赋值给first
            // first赋值给root
            TreeNode first = (TreeNode)tab[index], root = first, rl;
            
            // 删除有两个部分,一个是对节点的next和prev关系的删除
            // 一个是对节点parent和孩子关系的删除
            
            // 步骤1:下面先对节点的next和prev关系的删除
            // this为被删除的节点
            // this.next赋值给succ
            // this.prev赋值给pred
            // 前后关系 pred this succ
            TreeNode succ = (TreeNode)next, pred = prev;
            
            // 这个if,设置pred的next
            if (pred == null)
            	// 如果没有prev,将succ赋值给first,再赋值给tab[index],相当于跳过this
                tab[index] = first = succ;
            else
            	// 有prev,succ赋值给pred.next
                pred.next = succ;
            
            // 这个if,设置succ的prev
            if (succ != null)
            	// 如果有next,pred赋值给succ.prev
                succ.prev = pred;
            
            // 如果first为null,即代表succ和pred都是null,直接将这个桶设置为null,即可,已经做了,就直接返回
            if (first == null)
                return;
            
            // 将root的根节点赋值给root
            if (root.parent != null)
                root = root.root();
            
            // 步骤2:如果root,root的right或left,root的left的left,有一个为null,
            // 说明红黑树太稀疏了,反树化,调用first.untreeify(map),赋值给tab[index],然后返回
            // root.left赋值给rl
            if (root == null || root.right == null ||
                (rl = root.left) == null || rl.left == null) {
                tab[index] = first.untreeify(map);  // too small
                return;
            }
            
            // 步骤3:判断树节点的情况
            //  p = tab[index = (n - 1) & hash]
            //  node = ((TreeNode)p).getTreeNode(hash, key);
            //  ((TreeNode)node).removeTreeNode(this, tab, movable);
            // this是hash对应的桶下,对应的key对应的节点,然后对它调用removeTreeNode方法
            // this赋值给p,left赋值给pl,right赋值给pr
            TreeNode p = this, pl = left, pr = right, replacement;
            if (pl != null && pr != null) {
            	// 如果pl和pr都不为null
            	// pr赋值给s
                TreeNode s = pr, sl;
                // 将s最最左孩子赋值给s(即被删除节点的右孩子的最最左孩子)
                while ((sl = s.left) != null) // find successor
                    s = sl;
                // 步骤3.1:将s和p的颜色转换
                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
                // s.right赋值给sr
                TreeNode sr = s.right;
                // p.parent赋值给pp
                TreeNode pp = p.parent;
                
                // 步骤3.2 设置p和s以及它们的孩子,父亲间的关系
                if (s == pr) { // p was s's direct parent
                	// 如果s和pr相同,代表p的右孩子是s,而且s没有左孩子,p是s的父亲
                	// 设置p.parent为s,s.right为p,互换父子关系
                    p.parent = s;
                    s.right = p;
                }
                else {
                	// p不是s的父亲,s.parent赋值给sp
                    TreeNode sp = s.parent;
                    // sp赋值给p.parent                    
                    if ((p.parent = sp) != null) {
                    	// 如果sp不为null,设置sp的left/right为p
                        if (s == sp.left)
                            sp.left = p;
                        else
                            sp.right = p;
                    }
                    // pr赋值给s.right
                    if ((s.right = pr) != null)
                    	// 如果pr不为null,设置pr.parent为s
                        pr.parent = s;
                }
                // 步骤3.3:设置p,sr,pl,
                // 设置p.left为null
                p.left = null;
                // 设置p.right为sr
                if ((p.right = sr) != null)
                	// 如果sr不为null,设置sr.parent为null
                    sr.parent = p;
                // 设置s.left为pl
                if ((s.left = pl) != null)
                	// 如果pl不为null,设置pl.parent为s
                    pl.parent = s;
                // 设置s.parent为pp
                if ((s.parent = pp) == null)
                	// 如果pp为null,设置root为s
                    root = s;
                // 如果pp不为null,设置pp.left/right为s
                else if (p == pp.left)
                    pp.left = s;
                else
                    pp.right = s;
                // 如果sr不为null,设置replacement为sr,否则为p
                if (sr != null)
                    replacement = sr;
                else
                    replacement = p;
            }
            // 如果p只有左孩子,replacement = pl
            // 如果p只有右孩子,replacement = pr
            // 如果p没有孩子,replacement = p            
            else if (pl != null)
                replacement = pl;
            else if (pr != null)
                replacement = pr;
            else
                replacement = p;
            
            if (replacement != p) {
            	// 如果replacement不为p,即p有左或右孩子,或者sr为null
            	// 设置replacement.parent = p.parent
            	// 设置pp为p.parent
                TreeNode pp = replacement.parent = p.parent;
                if (pp == null)
                	// 如果pp为null,设置root为replacement
                    root = replacement;
                // 否则,设置pp.left/right为replacement
                else if (p == pp.left)
                    pp.left = replacement;
                else
                    pp.right = replacement;
                // p的left,right,parent都设置为null
                p.left = p.right = p.parent = null;
            }

            // 如果p为红色,则删除即可,r为root节点
            // 如果p为黑色,删除影响平衡,调用balanceDeletion,r为返回的节点
            TreeNode r = p.red ? root : balanceDeletion(root, replacement);

            if (replacement == p) {  // detach
            	// 如果replacement为p
            	// 设置pp为p.parent
                TreeNode pp = p.parent;
                // 设置p的parent为null
                p.parent = null;
                if (pp != null) {
                	// 设置pp的left/right为null
                    if (p == pp.left)
                        pp.left = null;
                    else if (p == pp.right)
                        pp.right = null;
                }
            }
            // 一般movable为true
            if (movable)
            	// 将r变成tab的桶节点
                moveRootToFront(tab, r);
        }

        /**
         * 将一个树桶的节点分割为低位和高位的树桶,或者如果当前的太小了,反树化。
         * 仅仅当resize时调用,看上面关于分割的位的讨论。
         *
         * @param map the map
         * @param tab the table for recording bin heads
         * @param index the index of the table being split
         * @param bit the bit of hash to split on
         */
        final void split(HashMap map, Node[] tab, int index, int bit) {
            TreeNode b = this;
            // Relink into lo and hi lists, preserving order
            TreeNode loHead = null, loTail = null;
            TreeNode hiHead = null, hiTail = null;
            int lc = 0, hc = 0;
            // oldTab[j]赋值给e
            // ((TreeNode)e).split(this, newTab, j, oldCap);
            // 设置e为b,也就是this,也就是树桶的第一个节点
            // 从e开始,不断e.next进行循环
            for (TreeNode e = b, next; e != null; e = next) {
                next = (TreeNode)e.next;
                // 设置e.next为null
                e.next = null;
                // bit就是oldCap,二进制位10000
                // 如果hash&bit为0,放在lo的队尾,lc++
                if ((e.hash & bit) == 0) {
                    if ((e.prev = loTail) == null)
                        loHead = e;
                    else
                        loTail.next = e;
                    loTail = e;
                    ++lc;
                }
                // 如果hash&bit为1,放在hi的队尾,hc++
                else {
                    if ((e.prev = hiTail) == null)
                        hiHead = e;
                    else
                        hiTail.next = e;
                    hiTail = e;
                    ++hc;
                }
            }

            if (loHead != null) {
                if (lc <= UNTREEIFY_THRESHOLD)
                	// 如果lc<=6,tab[index]为loHead的反树化结果
                    tab[index] = loHead.untreeify(map);
                else {
                	// 如果lc>6,tab[index] = loHead
                    tab[index] = loHead;
                    if (hiHead != null) // (else is already treeified)
                    	// 如果hiHead不为null,树化loHead
                        loHead.treeify(tab);
                }
            }
            if (hiHead != null) {
                if (hc <= UNTREEIFY_THRESHOLD)
                	// 如果hc<=6,tab[index + bit]为hiHead的反树化结果
                    tab[index + bit] = hiHead.untreeify(map);
                else {
                	// 如果hc>6,tab[index + bit] = hiHead
                    tab[index + bit] = hiHead;
                    if (loHead != null)
                    	// 如果loHead不为null,树化hiHead
                        hiHead.treeify(tab);
                }
            }
        }

        /* ------------------------------------------------------------ */
        // Red-black tree methods, all adapted from CLR

        // 左旋操作,其中root为根节点,p为当前节点,r为p的右节点,rl为r的左节点,pp为p的父节点
        // 左旋之后,r替换p的位置,rl挪到p的右节点
        // 节点位置变换之后,既要改变其父节点的left/right值,也要改变当前节点中parent的值,
        // 改变是双向的,父子均有指向,改变之后均要修改
        static  TreeNode rotateLeft(TreeNode root,
                                              TreeNode p) {
            TreeNode r, pp, rl;
            if (p != null && (r = p.right) != null) {
                if ((rl = p.right = r.left) != null)
                    rl.parent = p;
                if ((pp = r.parent = p.parent) == null)
                    (root = r).red = false;
                else if (pp.left == p)
                    pp.left = r;
                else
                    pp.right = r;
                r.left = p;
                p.parent = r;
            }
            return root;
        }

        static  TreeNode rotateRight(TreeNode root,
                                               TreeNode p) {
            TreeNode l, pp, lr;
            if (p != null && (l = p.left) != null) {
                if ((lr = p.left = l.right) != null)
                    lr.parent = p;
                if ((pp = l.parent = p.parent) == null)
                    (root = l).red = false;
                else if (pp.right == p)
                    pp.right = l;
                else
                    pp.left = l;
                l.right = p;
                p.parent = l;
            }
            return root;
        }

        static  TreeNode balanceInsertion(TreeNode root,
                                                    TreeNode x) {
            x.red = true;
            for (TreeNode xp, xpp, xppl, xppr;;) {
                if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                else if (!xp.red || (xpp = xp.parent) == null)
                    return root;
                if (xp == (xppl = xpp.left)) {
                    if ((xppr = xpp.right) != null && xppr.red) {
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.right) {
                            root = rotateLeft(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }
                else {
                    if (xppl != null && xppl.red) {
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.left) {
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }

        static  TreeNode balanceDeletion(TreeNode root,
                                                   TreeNode x) {
            for (TreeNode xp, xpl, xpr;;)  {
                if (x == null || x == root)
                    return root;
                else if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                else if (x.red) {
                    x.red = false;
                    return root;
                }
                else if ((xpl = xp.left) == x) {
                    if ((xpr = xp.right) != null && xpr.red) {
                        xpr.red = false;
                        xp.red = true;
                        root = rotateLeft(root, xp);
                        xpr = (xp = x.parent) == null ? null : xp.right;
                    }
                    if (xpr == null)
                        x = xp;
                    else {
                        TreeNode sl = xpr.left, sr = xpr.right;
                        if ((sr == null || !sr.red) &&
                            (sl == null || !sl.red)) {
                            xpr.red = true;
                            x = xp;
                        }
                        else {
                            if (sr == null || !sr.red) {
                                if (sl != null)
                                    sl.red = false;
                                xpr.red = true;
                                root = rotateRight(root, xpr);
                                xpr = (xp = x.parent) == null ?
                                    null : xp.right;
                            }
                            if (xpr != null) {
                                xpr.red = (xp == null) ? false : xp.red;
                                if ((sr = xpr.right) != null)
                                    sr.red = false;
                            }
                            if (xp != null) {
                                xp.red = false;
                                root = rotateLeft(root, xp);
                            }
                            x = root;
                        }
                    }
                }
                else { // symmetric
                    if (xpl != null && xpl.red) {
                        xpl.red = false;
                        xp.red = true;
                        root = rotateRight(root, xp);
                        xpl = (xp = x.parent) == null ? null : xp.left;
                    }
                    if (xpl == null)
                        x = xp;
                    else {
                        TreeNode sl = xpl.left, sr = xpl.right;
                        if ((sl == null || !sl.red) &&
                            (sr == null || !sr.red)) {
                            xpl.red = true;
                            x = xp;
                        }
                        else {
                            if (sl == null || !sl.red) {
                                if (sr != null)
                                    sr.red = false;
                                xpl.red = true;
                                root = rotateLeft(root, xpl);
                                xpl = (xp = x.parent) == null ?
                                    null : xp.left;
                            }
                            if (xpl != null) {
                                xpl.red = (xp == null) ? false : xp.red;
                                if ((sl = xpl.left) != null)
                                    sl.red = false;
                            }
                            if (xp != null) {
                                xp.red = false;
                                root = rotateRight(root, xp);
                            }
                            x = root;
                        }
                    }
                }
            }
        }

        /**
         * 递归不变量检查
         */
        static  boolean checkInvariants(TreeNode t) {
        	// tp为parent,tl为left,tr为right
            TreeNode tp = t.parent, tl = t.left, tr = t.right,
            // rb为prev,tn为next		
                tb = t.prev, tn = (TreeNode)t.next;
            // 校验prev的next
            if (tb != null && tb.next != t)
                return false;
            // 校验next的prev
            if (tn != null && tn.prev != t)
                return false;
            // 校验parent的子孩子
            if (tp != null && t != tp.left && t != tp.right)
                return false;
            // 校验left的父亲,并且parent的hash要大于left的hash
            if (tl != null && (tl.parent != t || tl.hash > t.hash))
                return false;
            // 校验right的父亲,并且parent的hash要小于right的hash
            if (tr != null && (tr.parent != t || tr.hash < t.hash))
                return false;
            // 如果自己,left,right都为红色,就错了
            if (t.red && tl != null && tl.red && tr != null && tr.red)
                return false;
            // 递归校验left和right
            if (tl != null && !checkInvariants(tl))
                return false;
            if (tr != null && !checkInvariants(tr))
                return false;
            return true;
        }
    }

jdk1.8和1.7之间HashMap的区别

数据结构

java容器 类HashMap源码分析_第8张图片

重要参数

HashMap中的主要参数 同 JDK 1.7 ,即:容量、加载因子、扩容阈值

但由于数据结构中引入了 红黑树,故加入了 与红黑树相关的参数。

 /** 
   * 主要参数 同  JDK 1.7 
   * 即:容量、加载因子、扩容阈值(要求、范围均相同)
   */

  // 1. 容量(capacity): 必须是2的幂 & <最大容量(2的30次方)
  static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 默认容量 = 16 = 1<<4 = 00001中的1向左移4位 = 10000 = 十进制的2^4=16
  static final int MAXIMUM_CAPACITY = 1 << 30; // 最大容量 =  2的30次方(若传入的容量过大,将被最大值替换)

  // 2. 加载因子(Load factor):HashMap在其容量自动增加前可达到多满的一种尺度 
  final float loadFactor; // 实际加载因子
  static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认加载因子 = 0.75

  // 3. 扩容阈值(threshold):当哈希表的大小 ≥ 扩容阈值时,就会扩容哈希表(即扩充HashMap的容量) 
  // a. 扩容 = 对哈希表进行resize操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数
  // b. 扩容阈值 = 容量 x 加载因子
  int threshold;

  // 4. 其他
  transient Node[] table;  // 存储数据的Node类型 数组,长度 = 2的幂;数组的每个元素 = 1个单链表
  transient int size;// HashMap的大小,即 HashMap中存储的键值对的数量
 

  /** 
   * 与红黑树相关的参数
   */
   // 1. 桶的树化阈值:即 链表转成红黑树的阈值,在存储数据时,当链表长度 > 该值时,则将链表转换成红黑树
   static final int TREEIFY_THRESHOLD = 8; 
   // 2. 桶的链表还原阈值:即 红黑树转为链表的阈值,当在扩容(resize())时(此时HashMap的数据存储位置会重新计算),在重新计算存储位置后,当原有的红黑树内数量 < 6时,则将 红黑树转换成链表
   static final int UNTREEIFY_THRESHOLD = 6;
   // 3. 最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即 将链表 转换成红黑树)
   // 否则,若桶内元素太多时,则直接扩容,而不是树形化
   // 为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD
   static final int MIN_TREEIFY_CAPACITY = 64;
  

java容器 类HashMap源码分析_第9张图片

java容器 类HashMap源码分析_第10张图片

声明1个 HashMap的对象

1.8的构造函数 类似 JDK 1.7,具体解析可以看前面

此处仅用于接收初始容量大小(capacity)、加载因子(Load factor),但仍无真正初始化哈希表,即初始化存储数组table

此处先给出结论:真正初始化哈希表(初始化存储数组table)是在第1次添加键值对时,即第1次调用put()时。下面会详细说明

向HashMap添加数据(成对 放入 键 - 值对)

在该步骤中,与JDK 1.7的差别较大:

java容器 类HashMap源码分析_第11张图片

添加数据的流程如下

java容器 类HashMap源码分析_第12张图片

 /**
   * 函数使用原型
   */
   map.put("Android", 1);
        map.put("Java", 2);
        map.put("iOS", 3);
        map.put("数据挖掘", 4);
        map.put("产品经理", 5);

   /**
     * 源码分析:主要分析HashMap的put函数
     */
    public V put(K key, V value) {
        // 1. 对传入数组的键Key计算Hash值 ->>分析1
        // 2. 再调用putVal()添加数据进去 ->>分析2
        return putVal(hash(key), key, value, false, true);
    }

hash(key)

   /**
     * 分析1:hash(key)
     * 作用:计算传入数据的哈希码(哈希值、Hash值)
     * 该函数在JDK 1.7 和 1.8 中的实现不同,但原理一样 = 扰动函数 = 使得根据key生成的哈希码(hash值)分布更加均匀、更具备随机性,避免出现hash值冲突(即指不同key但生成同1个hash值)
     * JDK 1.7 做了9次扰动处理 = 4次位运算 + 5次异或运算
     * JDK 1.8 简化了扰动函数 = 只做了2次扰动 = 1次位运算 + 1次异或运算
     */

      // JDK 1.7实现:将 键key 转换成 哈希码(hash值)操作  = 使用hashCode() + 4次位运算 + 5次异或运算(9次扰动)
      static final int hash(int h) {
        h ^= k.hashCode(); 
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
     }

      // JDK 1.8实现:将 键key 转换成 哈希码(hash值)操作 = 使用hashCode() + 1次位运算 + 1次异或运算(2次扰动)
      // 1. 取hashCode值: h = key.hashCode() 
      // 2. 高位参与低位的运算:h ^ (h >>> 16)  
      static final int hash(Object key) {
           int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
            // a. 当key = null时,hash值 = 0,所以HashMap的key 可为null      
            // 注:对比HashTable,HashTable对key直接hashCode(),若key为null时,会抛出异常,所以HashTable的key不可为null
            // b. 当key ≠ null时,则通过先计算出 key的 hashCode()(记为h),然后 对哈希码进行 扰动处理: 按位 异或(^) 哈希码自身右移16位后的二进制
     }

   /**
     * 计算存储位置的函数分析:indexFor(hash, table.length)
     * 注:该函数仅存在于JDK 1.7 ,JDK 1.8中实际上无该函数(直接用1条语句判断写出),但原理相同
     * 为了方便讲解,故提前到此讲解
     */
     static int indexFor(int h, int length) {  
          return h & (length-1); 
          // 将对哈希码扰动处理后的结果 与运算(&) (数组长度-1),最终得到存储在数组table的位置(即数组下标、索引)
          }

总结 计算存放在数组 table 中的位置(即数组下标、索引)的过程

此处与 JDK 1.7的区别在于:hash值的求解过程中 哈希码的二次处理方式(扰动处理)

 hash值的求解过程

java容器 类HashMap源码分析_第13张图片

java容器 类HashMap源码分析_第14张图片

在了解 如何计算存放数组table 中的位置 后,所谓 知其然 而 需知其所以然,下面我将讲解为什么要这样计算,即主要解答以下3个问题:

为什么不直接采用经过hashCode()处理的哈希码 作为 存储数组table的下标位置?

为什么采用 哈希码 与运算(&) (数组长度-1) 计算数组下标?

为什么在计算数组下标前,需对哈希码进行二次处理:扰动处理?

在回答这3个问题前,请大家记住一个核心思想:

所有处理的根本目的,都是为了提高 存储key-value的数组下标位置 的随机性 & 分布均匀性,尽量避免出现hash值冲突。即:对于不同key,存储的数组下标位置要尽可能不一样

问题1:为什么不直接采用经过hashCode()处理的哈希码 作为 存储数组table的下标位置?

结论:容易出现 哈希码 与 数组大小范围不匹配的情况,即 计算出来的哈希码可能 不在数组大小范围内,从而导致无法匹配存储位置

原因描述

java容器 类HashMap源码分析_第15张图片

  • 为了解决 “哈希码与数组大小范围不匹配” 的问题,HashMap给出了解决方案:哈希码 与运算(&) (数组长度-1),即问题3

问题2:为什么采用 哈希码 与运算(&) (数组长度-1) 计算数组下标?

结论:根据HashMap的容量大小(数组长度),按需取 哈希码一定数量的低位 作为存储的数组下标位置,从而 解决 “哈希码与数组大小范围不匹配” 的问题

java容器 类HashMap源码分析_第16张图片

问题3:为什么在计算数组下标前,需对哈希码进行二次处理:扰动处理?

结论:加大哈希码低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性 & 均匀性,最终减少Hash冲突

java容器 类HashMap源码分析_第17张图片

putVal(hash(key), key, value, false, true);

此处有2个主要讲解点:

计算完存储位置后,具体该如何 存放数据 到哈希表中

具体如何扩容,即 扩容机制

主要讲解点1:计算完存储位置后,具体该如何存放数据到哈希表中

由于数据结构中加入了红黑树,所以在存放数据到哈希表中时,需进行多次数据结构的判断:数组、红黑树、链表

JDK 1.7的区别: JDK 1.7只需判断 数组 & 链表

 

java容器 类HashMap源码分析_第18张图片

主要讲解点2:扩容机制(即 resize()函数方法)

java容器 类HashMap源码分析_第19张图片

此处主要讲解: JDK 1.8扩容时,数据存储位置重新计算的方式

java容器 类HashMap源码分析_第20张图片

java容器 类HashMap源码分析_第21张图片

数组位置转换的示意图

java容器 类HashMap源码分析_第22张图片

与 JDK 1.7的区别

java容器 类HashMap源码分析_第23张图片

从HashMap中获取数据

假如理解了上述put()函数的原理,那么get()函数非常好理解,因为二者的过程原理几乎相同

get()函数的流程如下:

java容器 类HashMap源码分析_第24张图片

对HashMap的其他操作

关于上述方法的源码的原理 同 JDK 1.7,此处不作过多描述

关于HashMap的其他问题

哈希表如何解决Hash冲突

java容器 类HashMap源码分析_第25张图片

为什么HashMap具备下述特点:键-值(key-value)都允许为空、线程不安全、不保证有序、存储位置随时间变化

java容器 类HashMap源码分析_第26张图片

 

jdk1.7的resize方法

/**
   * 源码分析:resize(2 * table.length)
   * 作用:当容量不足时(容量 > 阈值),则扩容(扩到2倍)
   */ 
   void resize(int newCapacity) {  
    
    // 1. 保存旧数组(old table) 
    Entry[] oldTable = table;  

    // 2. 保存旧容量(old capacity ),即数组长度
    int oldCapacity = oldTable.length; 

    // 3. 若旧容量已经是系统默认最大容量了,那么将阈值设置成整型的最大值,退出    
    if (oldCapacity == MAXIMUM_CAPACITY) {  
        threshold = Integer.MAX_VALUE;  
        return;  
    }  
  
    // 4. 根据新容量(2倍容量)新建1个数组,即新table  
    Entry[] newTable = new Entry[newCapacity];  

    // 5. (重点分析)将旧数组上的数据(键值对)转移到新table中,从而完成扩容 ->>分析1.1 
    transfer(newTable); 

    // 6. 新数组table引用到HashMap的table属性上
    table = newTable;  

    // 7. 重新设置阈值  
    threshold = (int)(newCapacity * loadFactor); 
} 

 /**
   * 分析1.1:transfer(newTable); 
   * 作用:将旧数组上的数据(键值对)转移到新table中,从而完成扩容
   * 过程:按旧链表的正序遍历链表、在新链表的头部依次插入
   */ 
void transfer(Entry[] newTable) {
      // 1. src引用了旧数组
      Entry[] src = table; 

      // 2. 获取新数组的大小 = 获取新容量大小                 
      int newCapacity = newTable.length;

      // 3. 通过遍历 旧数组,将旧数组上的数据(键值对)转移到新数组中
      for (int j = 0; j < src.length; j++) { 
          // 3.1 取得旧数组的每个元素  
          Entry e = src[j];           
          if (e != null) {
              // 3.2 释放旧数组的对象引用(for循环后,旧数组不再引用任何对象)
              src[j] = null; 

              do { 
                  // 3.3 遍历 以该数组元素为首 的链表
                  // 注:转移链表时,因是单链表,故要保存下1个结点,否则转移后链表会断开
                  Entry next = e.next; 
                 // 3.3 重新计算每个元素的存储位置
                 int i = indexFor(e.hash, newCapacity); 
                 // 3.4 将元素放在数组上:采用单链表的头插入方式 = 在链表头上存放数据 = 将数组位置的原有数据放在后1个指针、将需放入的数据放到数组位置中
                 // 即 扩容后,可能出现逆序:按旧链表的正序遍历链表、在新链表的头部依次插入
                 e.next = newTable[i]; 
                 newTable[i] = e;  
                 // 访问下1个Entry链上的元素,如此不断循环,直到遍历完该链表上的所有节点
                 e = next;             
             } while (e != null);
             // 如此不断循环,直到遍历完数组上的所有数据元素
         }
     }
 }

从上面可看出:在扩容resize()过程中,在将旧数组上的数据 转移到 新数组上时,转移数据操作 = 按旧链表的正序遍历链表、在新链表的头部依次插入,即在转移数据、扩容后,容易出现链表逆序的情况

设重新计算存储位置后不变,即扩容前 = 1->2->3,扩容后 = 3->2->1

此时若(多线程)并发执行 put()操作,一旦出现扩容情况,则 容易出现 环形链表,从而在获取数据、遍历链表时 形成死循环(Infinite Loop),即 死锁的状态,具体请看下图:

初始状态、步骤1、步骤2

java容器 类HashMap源码分析_第27张图片

java容器 类HashMap源码分析_第28张图片

注:由于 JDK 1.8 转移数据操作 = 按旧链表的正序遍历链表、在新链表的尾部依次插入,所以不会出现链表 逆序、倒置的情况,故不容易出现环形链表的情况。

JDK 1.8 还是线程不安全,因为 无加同步锁保护

为什么 HashMap 中 String、Integer 这样的包装类适合作为 key 键

java容器 类HashMap源码分析_第29张图片

HashMap 中的 key若 Object类型, 则需实现哪些方法?

java容器 类HashMap源码分析_第30张图片

HashMap和HashTable的理解与区别

父类不同

HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary(已被废弃,详情看源代码)。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。

Hashtable比HashMap多提供了elments() 和contains() 两个方法。

elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。

contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。

null值问题

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明 。

HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

线程安全性

Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步

HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。具体的原因在下一篇文章中会详细进行分析。使用HashMap时就必须要自己增加同步处理,

虽然HashMap不是线程安全的,但是它的效率会比Hashtable要好很多。这样设计是合理的。在我们的日常使用当中,大部分时间是单线程操作的。HashMap把这部分操作解放出来了。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。

tip:HashMap是JDk1.2之后有的,而在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从此Map也有安全的了。也就就是有了ConcurrentHashMap(关于这个的理解下次有机会再写,或自行百度)

遍历方式不同

Hashtable、HashMap都使用了Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

HashMap的Iterator是fail-fast迭代器。当有其它线程改变了HashMap的结构(增加,删除,修改元素),将会抛出ConcurrentModificationException。不过,通过Iterator的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。

JDK8之前的版本中,Hashtable是没有fast-fail机制的。在JDK8及以后的版本中 ,Hashtable也是使用fast-fail的。(此处可以去看一下1.5和1.8JDK源码的对比)

初始容量不同

Hashtable的初始长度是11,之后每次扩充容量变为之前的2n+1(n为上一次的长度)

而HashMap的初始长度为16,之后每次扩充变为原来的两倍

创建时,如果给定了容量初始值,那么Hashtable会直接使用你给定的大小,而HashMap会将其扩充为2的幂次方大小。

计算哈希值的方法不同

为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置

Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。 然而除法运算是非常耗费时间的。效率很低

HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
 

你可能感兴趣的:(源码分析,java容器)