HashMap源码解读(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhanghanlun/article/details/80024081

1.前言

  在我们面试过程中,经常会遇到要求说HashMap的底层实现,在JDK源码中,Oracle公司给出了我们HashMap的源码,通过阅读HashMap的源码,我们可以很清楚的知道HashMap是怎么实现的。下面我们开始阅读HashMap的源码吧。

2.关于HashMap的类的继承与实现

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

通过上面的代码我们知道了HashMap继承了AbstractMap这个类,实现了Map,Cloneable还有Serializable这个接口

3.HashMap类中的常量

    private static final long serialVersionUID = 362498820763181265L;//序列化ID
    /**
     * 默认的初始容量一定是2的倍数,在这里是16
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 <<4;

    /**
     * 最大容量一定是2的倍数,而且小于2的30次方
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 默认的负载因子是0.75
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    /**
    * 当HashMap桶中的箱子的数量达到8的时候就会将
    * 箱子的数据结构由链表转换成红黑树
    */
    static final int TREEIFY_THRESHOLD = 8;
    /**
    * 由树转换成链表的阈值
    * 在HashMap进行扩容的时候,当树中结点的个数小于6的时候有,由树转换成链表
    */
    static final int UNTREEIFY_THRESHOLD = 6;
    /**
    * 桶可能被树化的最小容量,至少为4*TREEIFY_THRESHOLD,
    * 避免扩容和树化阈值之间的冲突。
    * 只有当表的容量达到64之后才能进行树化
    */
    static final int MIN_TREEIFY_CAPACITY = 64;
      /**
     * 表,数组实现的结构
     */
    transient Node<K,V>[] table;

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

    /**
     * HashMap中存在的键值对数量
     */
    transient int size;

    /**
     * HashMap结构被修改的次数
     */
    transient int modCount;

    /**
     * 下一个调整大小的值,容量*负载因子
     *
     * @serial
     */
    int threshold;

    /**
     * Hash Table的负载因子
     *
     * @serial
     */
    final float loadFactor;

4.HashMap中的数据结构

HashMap中在底层的实现主要是基于数组和链表实现的,当然还有红黑树。在处理冲突的时候应用的是链表和红黑树相结合的方法,具体的实现,请看下面的图片:
这里写图片描述
我们知道HashMap存储的数据都存放在Entry这个数据结构中。Entry是HashMap的存储结点。
具体的JDK源码如下:

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;//final类型
        final K key;   //final类型
        V value;
        Node<K,V> next;
        /**
        * 结点构造函数
        */
        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }
        /**
        * 计算HashCode
        * 是由key的hashCode和value的HashCode进行异或产生的。
        */
        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
        /**
        * 结点比较,地址相同则相同,Key和Value相同则相同。
        */
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

5.HashMap构造函数

HashMap一共4个构造函数,分别如下:

    /**
    * 默认构造函数,负载因子为默认的0.75
    */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
    /**
    * 构造函数初始化 初始容量和负载因子
    */
    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);
    }
    /**
    * 构造函数,对Map进行复制构造HashMap
    */
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }
    //承接上面的方法
    /**
     * Implements Map.putAll and Map constructor.
     *
     * @param m the map
     * @param evict false,当刚开始构造的时候
     */
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            //判断原先的table是否为空,初始化参数
            if (table == null) { // pre-size
                //计算需要的表的长度
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    //设置阈值
                    threshold = tableSizeFor(t);
            }
            //超过阈值,进行扩容
            else if (s > threshold)
                resize();
            //遍历Map插入Map的结点进入HashMap
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/zhanghanlun/article/details/80024081