HashMap的源码分析(一)

1.hashMap的关键值

  DEFAULT_INITIAL_CAPACITY:默认初始容量16,∈(0,1<<30),实际大小为2的整数次幂;

  DEFAULT_LOAD_FACTOR:默认加载因子0.75,

  threshold:阈值,resize的判断条件。(threshold=容量*加载因子)

2.hashMap 的构造函数

    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;
        threshold = initialCapacity;
        init();
    }

    public HashMap(int initialCapacity) { //指定容量,加载因子0.75
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public HashMap() { //默认容量16,加载因子0.75
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

    public HashMap(Map<? extends K, ? extends V> m) {//构造一个映射关系与指定 Map 相同的新 HashMap.(一直不明白这样构造和new HashMap(); 然后 map.putAll(map2) 有什么区别?希望看到的大神讲解一下··)
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        inflateTable(threshold);

        putAllForCreate(m);
    }

3.hashMap的get()、put()方法

  ①put

    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {   
            inflateTable(threshold);
        }
        if (key == null)      //如果key为nullreturn putForNullKey(value);   
        int hash = hash(key);  
        int i = indexFor(hash, table.length);  //key不为null,根据key的hash值计算出table位置  (i = hash & 容量 )
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {   
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  //遍历对比key==this.key?新值替换旧值,返回旧值:新增entry
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);//return null;    //返回值不为null,说明这次put发生了新旧值得替换
    }

    private V putForNullKey(V value) { //put进去key为null的键值对
        for (Entry<K,V> e = table[0]; e != null; e = e.next) { //key为null的entry默认放在table[0],遍历table[0]的entry
            if (e.key == null) { //若果以前有key为null的entry
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue; //新值替换旧值,并且返回旧值
            }
        }
        modCount++;
        addEntry(0, null, value, 0); //以前没有当前key值,新增entry,
        return null;
    }

    void addEntry(int hash, K key, V value, int bucketIndex) {//新增entry
        if ((size >= threshold) && (null != table[bucketIndex])) { //size(key-value对)达到阈值 && 当前table不是空的---》resize
            resize(2 * table.length); //扩容为当前2倍,根据新的容量重新计算分配map中entry的位置
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex); //新建entry
    }

    void createEntry(int hash, K key, V value, int bucketIndex) { //新建entry
        Entry<K,V> e = table[bucketIndex]; //那到当前table的第一个entry(马上第一要变第二了!)
        table[bucketIndex] = new Entry<>(hash, key, value, e); //把新entry插入到table的第一格
        size++; //key-value对数量加一
    }

  ②get

    public V get(Object key) {
        if (key == null)
            return getForNullKey();    //返回key为null的value 
        Entry<K,V> entry = getEntry(key);    //拿到key的entry return null == entry ? null : entry.getValue();  //返回entry的value
    }
    private V getForNullKey() { //如果map.get(null) 返回table[0]中key为null的value,没有返回null
        if (size == 0) { //hashMap已占用槽的长度
            return null;
        }
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }

    final Entry<K,V> getEntry(Object key) {
        if (size == 0) { //判断map中的key-value对不是0
            return null;
        }

        int hash = (key == null) ? 0 : hash(key); //获取key的hash值
        for (Entry<K,V> e = table[indexFor(hash, table.length)]; //通过hash值和容量计算出table位置n,遍历table[n]里面的entry对比key相等的返回entry
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

 ③remove

    public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);
        return (e == null ? null : e.value);  //remove方法返回删除掉的value
    }

    final Entry<K,V> removeEntryForKey(Object key) {
        if (size == 0) {
            return null;
        }
        int hash = (key == null) ? 0 : hash(key);
        int i = indexFor(hash, table.length); //通过hash计算index
        Entry<K,V> prev = table[i]; //首次遍历是未 table[i] 的头entry
        Entry<K,V> e = prev; //用于遍历的entry

        while (e != null) {
            Entry<K,V> next = e.next; //拿到后项entry
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) { //找到要删除的key的entry
                modCount++;
                size--; //删除后size减一
                if (prev == e) //如果要删除的是 table[i]的头entry
                    table[i] = next; //老二晋升为 table[i]的头entry
                else
                    prev.next = next; //前一entry的next指向后一entry(删除当前entry)
                e.recordRemoval(this);
                return e;
            }
            prev = e; //将当前entry设为前女友
            e = next; //下一个
        }

        return e;
    }

④clear

    public void clear() {
        modCount++;                   //对map的操作次数,用于迭代时的线程安全
        Arrays.fill(table, null);
        size = 0;                       //数组中的entry数量设为0,此时的容量没有缩小。仍为clear前的容量
    }

    public static void fill(Object[] a, Object val) {
        for (int i = 0, len = a.length; i < len; i++)        //遍历将数组的所有值设为null,
            a[i] = val;
    }

 ⑤containsValue

    public boolean containsValue(Object value) {
        if (value == null)
            return containsNullValue();

        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)          //遍历数组
            for (Entry e = tab[i] ; e != null ; e = e.next)        //遍历entry
                if (value.equals(e.value))
                    return true;
        return false;
    }

    private boolean containsNullValue() {
        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (e.value == null)
                    return true;
        return false;
    }
原文地址:https://www.cnblogs.com/caoyajun33-blog/p/7615132.html