JDK1.8集合框架源码分析三-------------HashMap

1.HashMap的一些重要成员属性

      1.1) 默认的初始容量 DEFAULT_INITIAL_CAPACITY = 1 << 4,官方建议必须时2的次方数

      1.2) 负载因子DEFAULT_LOAD_FACTOR = 0.75f; 用来HashMap扩容判断

      1.3) Node<K,V>[] table; ---容器中的元素

2.HashMap的构造方法

      1.1) 无参构造函数

      1.2) 带容量的有参构造函数

      1.3) 带容量和负载因子的有参构造函数

3.HashMap的hash方法

     3.1) step1: 获取到 key的hashcode值

     3.2) step2: 将step1计算得到的值无符号右移16位

     3.3) step3: 将 step1 和 step2 的结果异或运算得到结果

4.HashMap容器中的重要元素类Node的组成

    4.1) hash值

    4.2) key 和 value值

    4.3) hash值相同时,变成链表结果的下一个Node

    static class Node<K,V>{
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        public Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        @Override
        public String toString() {
            return key + " = " + value;
        }
        //设置成新值,返回旧值
        public final V setValue(V newValue) {
            V oldValue = value;
            this.value = newValue;
            return oldValue;
        }

        @Override
        public int hashCode() {
            return Objects.hash(key) ^ Objects.hash(value);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node<?, ?> node = (Node<?, ?>) o;
            return Objects.equals(key, node.key) &&
                    Objects.equals(value, node.value);
        }
    }

5.HashMap的put方法

     5.1) 计算出HashMap中数组所在的下标值---步骤3的hash值 和 HashMap容量的值减去1做与运算

            从上面的表格可以看出容量的大小,必须为2的次方数,不然最终数组会有下标遗漏 

    5.2) HashMap容器put方法的返回值是旧值

    5.3) HashMap扩容时,在进行元素的重新分配时,针对单向链表需要明确以下节点

           5.3.1) 在同一个链表中,则说明这个链表中所有元素的hash值是相同的

          5.3.2) HashMap扩容标准是2的次方数,从4->8->16....

          5.3.3) 从5.1)可以得知hash值二进制在旧的容量所在二进制所处的位置是0 还是1 ,即可计算出当前整个链表

在新的HashMap容器中所处的位置

    public V put(K key, V value) {
        return putVal(hash(key), key, value);
    }

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

    private V putVal(int hash, K key, V value) {
        //定义一个临时变量用来存储HashMap容器的容量大小
        int capacity;
        //定义一个新元素在HashMap中数组里面的下表位置
        int currentIndex;

        //把HashMap容器的元素赋值给一个临时变量
        Node<K, V>[] tempTable = table;
        //如果HashMap容器为空或者容量为0,则需要扩容
        if (tempTable == null || tempTable.length == 0) {
            tempTable = resize();
        }
        capacity = tempTable.length;
        //计算新增的值将要存储的位置
        currentIndex = (capacity - 1) & hash;
        //从HashMap中取出当前位置的元素
        Node<K, V> tempNode = tempTable[currentIndex];
        //如果HashMap容器的当前位置还没有存储元素
        //则直接把信元素赋值到这个位置即可
        if (tempNode == null) {
            tempTable[currentIndex] = new Node<>(hash, key, value, null);
        } else {
            Node<K, V> modifyNode = null;
            //如果当前位置已经存储了元素,则需要根据不同的情况来处理这个元素
            Node<K, V> currentNode = tempNode;
            //1.如果新增的元素的hash(key)相同,并且(key 的对象 和 当前对象 相等 || key!=null && key值和当前的key相等),
            // 则需要更新当前节点的值
            //2.如果当前节点的类型是红黑树,则进入红黑树的逻辑进行处理--这里不做说明
            //3.进入单线链表的循环处理,如果在链表中找到和新增的元素的hash(key),key值和当前节点的都相同,并且key!= null的节点
            //只需把这个节点的值更新即可,否则直接添加到链表的末尾
            K currentKey = currentNode.key;
            int currentHash = currentNode.hash;
            if (currentHash == hash && (currentKey == key || key != null && key.equals(currentKey))) {
                modifyNode = currentNode;
            } else if (currentNode instanceof TreeNode) {
                //TODO jdk1.8后才有的
            } else {
                for (int bitCount = 0; ; bitCount++) {
                    Node<K, V> nextNode = currentNode.next;
                    //如果当前节点的下一个节点为null,则到了单向链表的尾节点
                    //直接把新元素添加到单向链表的结尾即可
                    if (nextNode == null) {
                        nextNode.next = new Node<>(hash, key, value, null);
                        if (bitCount >= TREEIFY_THRESHOLD - 1) {
                            //TODO 如果单向链表的元素个数大于所设置的向红黑树转变的条件,则需要处理
                        }
                        break;
                    }
                    //如果当前节点的下一个节点不为null,则判断新节点和当前节点是否满足相同节点的条件
                    if (nextNode.hash == hash && (nextNode.key == key || key != null && key.equals(nextNode.key))) {
                        modifyNode = nextNode;
                        break;
                    }
                    //如果没有遍历到单向链表的末尾,并且新节点不是当前节点
                    //则继续遍历
                    currentNode = nextNode;
                }
            }

            //如果在单向链表中存在节点和新节点相同的条件,则只需要把旧节点的数据修改成新的值即可
            if (modifyNode != null) {
                V oldValue = modifyNode.value;
                //TODO 如果有参数设置,节点已经存在,切节点的值不为null就不在添加,则不需要更新节点的值
                modifyNode.value = value;
                return oldValue;
            }

        }

        size++;
        //如果容器中元素的个数大于
        // HashMap容器根据负载因子设置的阈值
        // 则需要扩容,并重新分配HashMap中元素的位置
        if (size > threshold) {
            resize();
        }
        return null;
    }

    /**
     * 初始化HashMap容器,或者重新分配HashMap容器中元素的位置
     * 因为当HashMap容器中元素超过一定的数量,需要扩容,
     * 而扩容之后元素hash值发生变化,所以需要重新分配HashMap容器中元素的位置
     */
    final Node<K, V>[] resize() {
        //定义一个临时变量存储旧的HashMap容器中的元素集合
        Node<K, V>[] oldTable = table;
        //旧HashMap容器的容量大小为
        int oldCapacity = oldTable == null ? 0 : oldTable.length;
        //旧的扩容标准
        int oldThreshold = threshold;
        //定义临时变量存储新容器容量和新扩容标准
        int newCapactity = 0;
        int newThreshold = 0;
        //如果旧的HashMap容器大于0
        if (oldCapacity > 0) {
            //如果旧的HashMap容器已经达到HashMap允许的最大容量
            //则只需把扩容标准放大到最大即可
            if (oldCapacity >= MAXIMUM_CAPACITY) {
                threshold = MAXIMUM_CAPACITY;
                return oldTable;
            }
            //如果旧的HashMap容器还没有达到HashMap允许的最大容量
            //则把旧的容量扩大两倍作为新的容器的容量
            newCapactity = oldCapacity << 1;
            //如果扩大后的容器容量小于HashMap允许的最大容量
            //并且大于等于默认的最小初始容量
            //则把旧的扩容标准加倍
            if (newCapactity < MAXIMUM_CAPACITY && newCapactity >= DEFAULT_INITIAL_CAPACITY) {
                newThreshold = oldThreshold << 1;
            }
        }
        //如果旧的扩容标准大于0
        else if (oldThreshold > 0) {
            newCapactity = oldThreshold;
        } else {
            // 如果上面两个条件都不满足,则取HashMap容器默认的标准
            newCapactity = DEFAULT_INITIAL_CAPACITY;
            newThreshold = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        threshold = newThreshold;
        //使用新的容量创建HashMap容器
        Node<K, V>[] newTable = (Node<K, V>[]) new Node[newCapactity];
        //将新HashMap容器赋值给HashMap容器
        table = newTable;
        //如果旧的HashMap容器不为空,则需要重新分配HashMap容器中的元素
        if (oldTable != null) {
            for (int i = 0; i < oldCapacity; i++) {
                Node<K, V> currentNode = oldTable[i];
                //旧HashMap容器当前位置不为空,则需要根据新的容量重新计算该元素应该存放的位置
                if (currentNode != null) {
                    oldTable[i] = null;//为了让GC回收
                    //判断当前节点是否有下下一个节点,如果没有,则直接进行元素位置的重新计算
                    if (currentNode.next == null) {
                        int currentHash = currentNode.hash;
                        int newIndex = currentHash & (newCapactity - 1);
                        newTable[newIndex] = currentNode;
                    } else if (currentNode instanceof TreeNode) {
                        //TODO 如果当前节点的类型是红黑树
                    } else {
                        //同一个单向链表中元素的hash值是相等的
                        //因此在新的HashMap容器中,这个链表中所有的元素,
                        // 也还是在相同的位置,并且是链表的格式存储
                        Node<K, V> highHeadNode = null;
                        Node<K, V> highTailNode = null;
                        Node<K, V> lowHeadNode = null;
                        Node<K, V> lowTailNode = null;
                        do {
                            int currentHash = currentNode.hash;
                            int hashLocation = currentHash & oldCapacity;
                            if (hashLocation == 0){
                                //如果尾部节点还没有设置,则说明此时还没有头结点
                                if(lowTailNode == null){
                                    lowHeadNode = currentNode;
                                }else{
                                    lowTailNode.next = currentNode;
                                }
                                lowTailNode = currentNode;
                            }else{
                                if(highTailNode == null){
                                    highHeadNode = currentNode;
                                }else{
                                    highTailNode.next = currentNode;
                                }
                                highTailNode = currentNode;
                            }
                            //继续循环当前节点的下一个节点
                            currentNode = currentNode.next;
                        } while (currentNode.next != null);
                        //如果hash&oldCapacity = 0 则说明这个链表的元素在新HashMap容器中,数组下表位置不变
                        if(lowTailNode != null){
                            lowTailNode.next = null;
                            newTable[i] = lowHeadNode;
                        }
                        if(highTailNode != null){
                            highTailNode.next = null;
                            newTable[i + oldCapacity] = highHeadNode;
                        }
                    }
                }
            }
        }

        return newTable;
    }

6.HashMap的get方法

    public V get(Object key) {

        Node<K, V> node = null;
        node = getNode(hash(key), key);

        return node == null ? null : node.value;
    }

    private Node<K, V> getNode(int hash, Object key) {
        Node<K, V>[] tempTable = table;
        int capacity = tempTable.length;
        //如果当前HashMap容器为空或者其容量为0,则直接返回null
        if (tempTable == null || capacity == 0) {
            return null;
        }

        //要查找的key值,如果存在,则在容器中的位置为
        int location = hash & (capacity - 1);
        Node<K, V> firstNode = tempTable[location];
        if (firstNode == null) {
            return null;
        }
        if (firstNode.hash == hash
                && (firstNode.key == key
                    || (key != null && key.equals(firstNode.key)))) {
            return firstNode;
        }
        Node<K,V> nextNode = firstNode.next;
        //是不是链表
        if(nextNode != null){
            if(nextNode instanceof TreeNode){
                //TODO 红黑树结构的处理
            }else{
                do{
                    if (nextNode.hash == hash
                            && (nextNode.key == key
                            || (key != null && key.equals(nextNode.key)))) {
                        return nextNode;
                    }
                    nextNode = nextNode.next;
                }while (nextNode != null);
            }
        }
        return null;
    }

7.HashMap的remove方法

    public V remove(Object key) {
        Node<K, V> removeNode = null;

        removeNode = removeNode(hash(key), key);

        return removeNode == null ? null : removeNode.value;

    }

    private Node<K, V> removeNode(int hash, Object key) {
        Node<K, V> removeNode = null;
        Node<K, V> prevNode = null;
        Node<K, V>[] tempTable = table;
        int capacity = tempTable.length;
        //如果当前HashMap容器为空或者其容量为0,则直接返回null
        if (tempTable == null || capacity == 0) {
            return null;
        }

        //要查找的key值,如果存在,则在容器中的位置为
        int location = hash & (capacity - 1);
        Node<K, V> firstNode = tempTable[location];
        if (firstNode == null) {
            return null;
        }

        if (firstNode.hash == hash
                && (firstNode.key == key
                || (key != null && key.equals(firstNode.key)))) {
            removeNode = firstNode;
            prevNode = firstNode;
        }
        Node<K, V> nextNode = firstNode.next;
        //是不是链表
        if (removeNode == null & nextNode != null) {
            if (nextNode instanceof TreeNode) {
                //TODO 红黑树结构的处理
            } else {
                do {
                    if (nextNode.hash == hash
                            && (nextNode.key == key
                            || (key != null && key.equals(nextNode.key)))) {
                        removeNode = nextNode;
                        break;
                    }
                    prevNode = nextNode;
                    nextNode = nextNode.next;
                } while (nextNode != null);
            }
        }
        //如果要删除的元素存在
        if (removeNode != null) {
            //如果删除的是
            if (removeNode instanceof TreeNode) {
                //TODO 红黑树
            }
            //如果删除不是单向链表,这个位置只有一个元素,并且匹配上了
            else if (removeNode == prevNode) {
                tempTable[location] = removeNode.next;
            }else{
                prevNode.next = removeNode.next;
            }
            --size;
            return removeNode;
        }
        return null;
    }

8.自己手写HashMap源码代码以及Junit测试类

package com.roger.collection.impl;

import javax.swing.tree.TreeNode;
import java.util.Objects;

public class RogerHashMap<K, V> {
    //单向链表转向红黑树的条件判断
    static final int TREEIFY_THRESHOLD = 8;
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
    //HashMap中数组的最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;
    static final float DEFAULT_LOAD_FACTOR = 0.75F;

    static class Node<K, V> {
        final int hash;
        final K key;
        V value;
        Node<K, V> next;

        public Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        @Override
        public String toString() {
            return key + " = " + value;
        }

        //设置成新值,返回旧值
        public final V setValue(V newValue) {
            V oldValue = value;
            this.value = newValue;
            return oldValue;
        }

        @Override
        public int hashCode() {
            return Objects.hash(key) ^ Objects.hash(value);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node<?, ?> node = (Node<?, ?>) o;
            return Objects.equals(key, node.key) &&
                    Objects.equals(value, node.value);
        }
    }

    //HashMap容器下一次扩容的标准
    //即当HashMap容器中元素的个数大于这个值
    //就会触发HashMap容器扩容
    //JDK1.8保证这个值是2的次方数
    int threshold;
    //负载因子
    final float loadFactor;
    //HashMap容器中元素的个数
    int size;

    public RogerHashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
    }

    public RogerHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public RogerHashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal initial capacity : " + initialCapacity);
        }

        if (initialCapacity > MAXIMUM_CAPACITY) {
            initialCapacity = MAXIMUM_CAPACITY;
        }

        if (loadFactor < 0) {
            throw new IllegalArgumentException("Illegal load factor : " + loadFactor);
        }

        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

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

    Node<K, V>[] table;

    public V get(Object key) {

        Node<K, V> node = null;
        node = getNode(hash(key), key);

        return node == null ? null : node.value;
    }

    private Node<K, V> getNode(int hash, Object key) {
        Node<K, V>[] tempTable = table;
        int capacity = tempTable.length;
        //如果当前HashMap容器为空或者其容量为0,则直接返回null
        if (tempTable == null || capacity == 0) {
            return null;
        }

        //要查找的key值,如果存在,则在容器中的位置为
        int location = hash & (capacity - 1);
        Node<K, V> firstNode = tempTable[location];
        if (firstNode == null) {
            return null;
        }
        if (firstNode.hash == hash
                && (firstNode.key == key
                || (key != null && key.equals(firstNode.key)))) {
            return firstNode;
        }
        Node<K, V> nextNode = firstNode.next;
        //是不是链表
        if (nextNode != null) {
            if (nextNode instanceof TreeNode) {
                //TODO 红黑树结构的处理
            } else {
                do {
                    if (nextNode.hash == hash
                            && (nextNode.key == key
                            || (key != null && key.equals(nextNode.key)))) {
                        return nextNode;
                    }
                    nextNode = nextNode.next;
                } while (nextNode != null);
            }
        }
        return null;
    }

    public V remove(Object key) {
        Node<K, V> removeNode = null;

        removeNode = removeNode(hash(key), key);

        return removeNode == null ? null : removeNode.value;

    }

    private Node<K, V> removeNode(int hash, Object key) {
        Node<K, V> removeNode = null;
        Node<K, V> prevNode = null;
        Node<K, V>[] tempTable = table;
        int capacity = tempTable.length;
        //如果当前HashMap容器为空或者其容量为0,则直接返回null
        if (tempTable == null || capacity == 0) {
            return null;
        }

        //要查找的key值,如果存在,则在容器中的位置为
        int location = hash & (capacity - 1);
        Node<K, V> firstNode = tempTable[location];
        if (firstNode == null) {
            return null;
        }

        if (firstNode.hash == hash
                && (firstNode.key == key
                || (key != null && key.equals(firstNode.key)))) {
            removeNode = firstNode;
            prevNode = firstNode;
        }
        Node<K, V> nextNode = firstNode.next;
        //是不是链表
        if (removeNode == null & nextNode != null) {
            if (nextNode instanceof TreeNode) {
                //TODO 红黑树结构的处理
            } else {
                do {
                    if (nextNode.hash == hash
                            && (nextNode.key == key
                            || (key != null && key.equals(nextNode.key)))) {
                        removeNode = nextNode;
                        break;
                    }
                    prevNode = nextNode;
                    nextNode = nextNode.next;
                } while (nextNode != null);
            }
        }
        //如果要删除的元素存在
        if (removeNode != null) {
            //如果删除的是
            if (removeNode instanceof TreeNode) {
                //TODO 红黑树
            }
            //如果删除不是单向链表,这个位置只有一个元素,并且匹配上了
            else if (removeNode == prevNode) {
                tempTable[location] = removeNode.next;
            }else{
                prevNode.next = removeNode.next;
            }
            --size;
            return removeNode;
        }
        return null;
    }

    public V put(K key, V value) {
        return putVal(hash(key), key, value);
    }

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

    private V putVal(int hash, K key, V value) {
        //定义一个临时变量用来存储HashMap容器的容量大小
        int capacity;
        //定义一个新元素在HashMap中数组里面的下表位置
        int currentIndex;

        //把HashMap容器的元素赋值给一个临时变量
        Node<K, V>[] tempTable = table;
        //如果HashMap容器为空或者容量为0,则需要扩容
        if (tempTable == null || tempTable.length == 0) {
            tempTable = resize();
        }
        capacity = tempTable.length;
        //计算新增的值将要存储的位置
        currentIndex = (capacity - 1) & hash;
        //从HashMap中取出当前位置的元素
        Node<K, V> tempNode = tempTable[currentIndex];
        //如果HashMap容器的当前位置还没有存储元素
        //则直接把信元素赋值到这个位置即可
        if (tempNode == null) {
            tempTable[currentIndex] = new Node<>(hash, key, value, null);
        } else {
            Node<K, V> modifyNode = null;
            //如果当前位置已经存储了元素,则需要根据不同的情况来处理这个元素
            Node<K, V> currentNode = tempNode;
            //1.如果新增的元素的hash(key)相同,并且(key 的对象 和 当前对象 相等 || key!=null && key值和当前的key相等),
            // 则需要更新当前节点的值
            //2.如果当前节点的类型是红黑树,则进入红黑树的逻辑进行处理--这里不做说明
            //3.进入单线链表的循环处理,如果在链表中找到和新增的元素的hash(key),key值和当前节点的都相同,并且key!= null的节点
            //只需把这个节点的值更新即可,否则直接添加到链表的末尾
            K currentKey = currentNode.key;
            int currentHash = currentNode.hash;
            if (currentHash == hash && (currentKey == key || key != null && key.equals(currentKey))) {
                modifyNode = currentNode;
            } else if (currentNode instanceof TreeNode) {
                //TODO jdk1.8后才有的
            } else {
                for (int bitCount = 0; ; bitCount++) {
                    Node<K, V> nextNode = currentNode.next;
                    //如果当前节点的下一个节点为null,则到了单向链表的尾节点
                    //直接把新元素添加到单向链表的结尾即可
                    if (nextNode == null) {
                        nextNode.next = new Node<>(hash, key, value, null);
                        if (bitCount >= TREEIFY_THRESHOLD - 1) {
                            //TODO 如果单向链表的元素个数大于所设置的向红黑树转变的条件,则需要处理
                        }
                        break;
                    }
                    //如果当前节点的下一个节点不为null,则判断新节点和当前节点是否满足相同节点的条件
                    if (nextNode.hash == hash && (nextNode.key == key || key != null && key.equals(nextNode.key))) {
                        modifyNode = nextNode;
                        break;
                    }
                    //如果没有遍历到单向链表的末尾,并且新节点不是当前节点
                    //则继续遍历
                    currentNode = nextNode;
                }
            }

            //如果在单向链表中存在节点和新节点相同的条件,则只需要把旧节点的数据修改成新的值即可
            if (modifyNode != null) {
                V oldValue = modifyNode.value;
                //TODO 如果有参数设置,节点已经存在,切节点的值不为null就不在添加,则不需要更新节点的值
                modifyNode.value = value;
                return oldValue;
            }

        }

        size++;
        //如果容器中元素的个数大于
        // HashMap容器根据负载因子设置的阈值
        // 则需要扩容,并重新分配HashMap中元素的位置
        if (size > threshold) {
            resize();
        }
        return null;
    }

    /**
     * 初始化HashMap容器,或者重新分配HashMap容器中元素的位置
     * 因为当HashMap容器中元素超过一定的数量,需要扩容,
     * 而扩容之后元素hash值发生变化,所以需要重新分配HashMap容器中元素的位置
     */
    final Node<K, V>[] resize() {
        //定义一个临时变量存储旧的HashMap容器中的元素集合
        Node<K, V>[] oldTable = table;
        //旧HashMap容器的容量大小为
        int oldCapacity = oldTable == null ? 0 : oldTable.length;
        //旧的扩容标准
        int oldThreshold = threshold;
        //定义临时变量存储新容器容量和新扩容标准
        int newCapactity = 0;
        int newThreshold = 0;
        //如果旧的HashMap容器大于0
        if (oldCapacity > 0) {
            //如果旧的HashMap容器已经达到HashMap允许的最大容量
            //则只需把扩容标准放大到最大即可
            if (oldCapacity >= MAXIMUM_CAPACITY) {
                threshold = MAXIMUM_CAPACITY;
                return oldTable;
            }
            //如果旧的HashMap容器还没有达到HashMap允许的最大容量
            //则把旧的容量扩大两倍作为新的容器的容量
            newCapactity = oldCapacity << 1;
            //如果扩大后的容器容量小于HashMap允许的最大容量
            //并且大于等于默认的最小初始容量
            //则把旧的扩容标准加倍
            if (newCapactity < MAXIMUM_CAPACITY && newCapactity >= DEFAULT_INITIAL_CAPACITY) {
                newThreshold = oldThreshold << 1;
            }
        }
        //如果旧的扩容标准大于0
        else if (oldThreshold > 0) {
            newCapactity = oldThreshold;
        } else {
            // 如果上面两个条件都不满足,则取HashMap容器默认的标准
            newCapactity = DEFAULT_INITIAL_CAPACITY;
            newThreshold = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        threshold = newThreshold;
        //使用新的容量创建HashMap容器
        Node<K, V>[] newTable = (Node<K, V>[]) new Node[newCapactity];
        //将新HashMap容器赋值给HashMap容器
        table = newTable;
        //如果旧的HashMap容器不为空,则需要重新分配HashMap容器中的元素
        if (oldTable != null) {
            for (int i = 0; i < oldCapacity; i++) {
                Node<K, V> currentNode = oldTable[i];
                //旧HashMap容器当前位置不为空,则需要根据新的容量重新计算该元素应该存放的位置
                if (currentNode != null) {
                    oldTable[i] = null;//为了让GC回收
                    //判断当前节点是否有下下一个节点,如果没有,则直接进行元素位置的重新计算
                    if (currentNode.next == null) {
                        int currentHash = currentNode.hash;
                        int newIndex = currentHash & (newCapactity - 1);
                        newTable[newIndex] = currentNode;
                    } else if (currentNode instanceof TreeNode) {
                        //TODO 如果当前节点的类型是红黑树
                    } else {
                        //同一个单向链表中元素的hash值是相等的
                        //因此在新的HashMap容器中,这个链表中所有的元素,
                        // 也还是在相同的位置,并且是链表的格式存储
                        Node<K, V> highHeadNode = null;
                        Node<K, V> highTailNode = null;
                        Node<K, V> lowHeadNode = null;
                        Node<K, V> lowTailNode = null;
                        do {
                            int currentHash = currentNode.hash;
                            int hashLocation = currentHash & oldCapacity;
                            if (hashLocation == 0) {
                                //如果尾部节点还没有设置,则说明此时还没有头结点
                                if (lowTailNode == null) {
                                    lowHeadNode = currentNode;
                                } else {
                                    lowTailNode.next = currentNode;
                                }
                                lowTailNode = currentNode;
                            } else {
                                if (highTailNode == null) {
                                    highHeadNode = currentNode;
                                } else {
                                    highTailNode.next = currentNode;
                                }
                                highTailNode = currentNode;
                            }
                            //继续循环当前节点的下一个节点
                            currentNode = currentNode.next;
                        } while (currentNode.next != null);
                        //如果hash&oldCapacity = 0 则说明这个链表的元素在新HashMap容器中,数组下表位置不变
                        if (lowTailNode != null) {
                            lowTailNode.next = null;
                            newTable[i] = lowHeadNode;
                        }
                        if (highTailNode != null) {
                            highTailNode.next = null;
                            newTable[i + oldCapacity] = highHeadNode;
                        }
                    }
                }
            }
        }

        return newTable;
    }
}
package com.roger.collection.impl;

import org.junit.Test;

import static org.junit.Assert.*;

public class RogerHashMapTest {

    @Test
    public void testPut() {

        RogerHashMap<String, Object> rogerHashMap = new RogerHashMap<>(2);

        rogerHashMap.put("name", "Roger");
        rogerHashMap.put("age", 12);
        rogerHashMap.put("address", "上海");
        rogerHashMap.remove("name");
        System.out.println("name:" + rogerHashMap.get("name"));
        System.out.println("age:" + rogerHashMap.get("age"));
        System.out.println("address:" + rogerHashMap.get("address"));

    }
}

猜你喜欢

转载自blog.csdn.net/lihongtai/article/details/84998024