Java 8 HashMap(一)—— 构造方法

一、类属性

    //默认容量16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
    //最大容量2的30次方
    static final int MAXIMUM_CAPACITY = 1 << 30;
    //默认加载因子0.75
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //单个节点上的链表长度大于8时转换为红黑树
    static final int TREEIFY_THRESHOLD = 8;
    //单个节点上的红黑树大小小于6时退化为链表
    static final int UNTREEIFY_THRESHOLD = 6;
    //当最小容量大于64时单个节点上的链表才有可能转换为红黑树
    static final int MIN_TREEIFY_CAPACITY = 64;

二、对象属性

    //Node数组
    transient Node<K, V>[] table;
    //Entry集合
    transient Set<Map.Entry<K, V>> entrySet;
    //当前Map的长度
    transient int size;
    /**
     * 已对HashMap进行结构修改的次数。
     * 结构修改是指更改HashMap中的节点或以其他方式修改其内部结构(例如,节点的增加和修改)的修改。
     * 此字段用于使HashMap的Collection-view上的迭代器快速失败。
     * (请参见ConcurrentModificationException)
     */
    transient int modCount;
    /**
     * 下一个要调整大小的大小值(capacity*loadFactor),扩容位置。
     */
    int threshold;
    /**
     * 加载因子
     */
    final float loadFactor;

三、构造方法中会用到的方法

   /**
     * @return 大于当前传入数字的最小2次幂的值,如果结果大于最大允许容量,则返回最大运行容量值
     */
    static int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        if (n < 0) {
            return 1;
        } else {
            if (n >= MAXIMUM_CAPACITY) {
                return MAXIMUM_CAPACITY;
            } else {
                return n + 1;
            }
        }
    }
   /**
     * @param evict 最初构造此Map时为false,否则为true(中继到afterNodeInsertion方法)。
     */
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        //获得参数Map的参数长度
        int s = m.size();
        if (s > 0) {
            //如果当前Map没有初始化
            if (table == null) {
                //计算参数Map出去当前Map的加载因子
                //作用在于如果参数Map大小+1设置为当前Map的threshold(扩容位置)是否会大于最大容量
                float ft = ((float) s / loadFactor) + 1.0F;
                //比较最大容量与ft,取小值;
                int t = ((ft < (float) MAXIMUM_CAPACITY) ?
                        (int) ft : MAXIMUM_CAPACITY);
                //如果t大于当前Map的threshold(扩容位置)
                if (t > threshold) {
                    //重新计算当前Map的扩容位置
                    threshold = tableSizeFor(t);
                }
            } else if (s > threshold) {
                //如果当前Map已经初始化,且参数Map的大小大于扩容位置
                //进行扩容
                resize();
            }
            //遍历参数Map的Node节点放入当前Map
            for (Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

四、构造方法

    /**
     * 用HashMap(int initialCapacity, float loadFactor)和HashMap(int initialCapacity)
     * 方法创建HashMap对象会初始化扩容位置threshold,大小为tableSizeFor(initialCapacity)
     * 但是在初始化后会进行修正
     */

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal initial capacity: " +
                    initialCapacity);
        }
        if (initialCapacity > MAXIMUM_CAPACITY) {
            initialCapacity = MAXIMUM_CAPACITY;
        }
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new IllegalArgumentException("Illegal load factor: " +
                    loadFactor);
        }
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

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

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

    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

五、其他一些方法

为下面的章节做铺垫

    /**
     * @return key为null返回0,key不为空返回key的后16位和前16位的异或运算结果
     */
    static <K> int hash(K key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
    Node<K, V> newNode(int hash, K key, V value, Node<K, V> next) {
        return new Node<>(hash, key, value, next);
    }

    /*用于从TreeNodes转换为Node*/
    Node<K, V> replacementNode(Node<K, V> p, Node<K, V> next) {
        return new Node<>(p.hash, p.key, p.value, next);
    }

    TreeNode<K, V> newTreeNode(int hash, K key, V value, Node<K, V> next) {
        return new TreeNode<>(hash, key, value, next);
    }

    /*用于从Node转换为TreeNode*/
    TreeNode<K, V> replacementTreeNode(Node<K, V> p, Node<K, V> next) {
        return new TreeNode<>(p.hash, p.key, p.value, next);
    }
上一篇:【Java集合】ArrayList类 扩容机制 底层源码分析


下一篇:HashMap的初始容量大小和长度扩展。hash算法