HashMap源码分析

继承关系

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

内部变量

 /**
     * The default initial capacity - MUST be a power of two.
     */
	//初始化table数组大小
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
	 //table数组的最大长度,2的30次方
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * The load factor used when none specified in constructor.
     */
	 //table数组的扩容影响因子,默认保存的节点数量超过了 数组长度*factor 就double一下长度
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
	 //HashMap实现的底层数据结构,数组
    transient Entry[] table;

    /**
     * The number of key-value mappings contained in this map.
     */
	 //Map中保存的key-value节点数,用来判断数组扩容条件
    transient int size;

    /**
     * The next size value at which to resize (capacity * load factor).
     * @serial
     */
	 //扩容的阈值
    int threshold;

    /**
     * The load factor for the hash table.
     *
     * @serial
     */
	 //扩容因子可以由调用者传入
    final float loadFactor;

    /**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     */
    transient volatile int modCount;

HashMap数据存储示意图


Entry数据结构

HashMap的一个内部静态类

        final K key;
        V value;
	//当不同的key定位到table数组中同一个索引后,需要用链表把这些冲突的entry串起来
        Entry<K,V> next;
		
	//key.hashCode经过hash算法计算而来
        final int hash;

put过程

1.key如果是null,调用putForNullKey,在table[0]上的链表进行遍历:
    如果key为null存在,更新value,返回旧值
    如果不存在,调用addEntry,new一个Entry,key为null,hash位0,插入到table[0]上,插入到链表头部
2.key不为null,计算hash值,计算数组索引index
   int hash = hash(key.hashCode());
   int i = indexFor(hash, table.length);
  在索引为i的table[i]指向的链表上,进行遍历,
      如果key存在(key值相等,且hash值相等),更新value ;  
      如果key不存在,调用addEntry(hash, key, value, i);

分析addEntry方法

void addEntry(int hash, K key, V value, int bucketIndex) {
	Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }

上面这段代码很简单了吧,就是在头部插入新的key-value,维护链表顺序,同时,如果保存的节点数大于阈值,则进行数组扩容

扩容分析

void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
		//如果数组长度已经最大,将阈值改为Integer.MAX_VALUE,不做任何修改
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }
        //创建新数组
        Entry[] newTable = new Entry[newCapacity];
		//将节点从老的数组中迁移到新的数组中
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
}

void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
}

删除key

final Entry<K,V> removeEntryForKey(Object key) {
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                modCount++;
                size--;
                if (prev == e)
                    table[i] = next;
                else
                    prev.next = next;
                e.recordRemoval(this);
                return e;
            }
            prev = e;
            e = next;
        }

        return e;
    }

如果你对链表这种数据结构很熟悉的话,上面这段代码就没什么意思了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值