1. 程式人生 > >JDK1.8集合框架原始碼分析三-------------HashMap

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"));

    }
}