HashMap源码分析

来源:互联网 发布:淘宝店家联系方式 编辑:程序博客网 时间:2024/05/21 09:53

1.Hashmap中几个重要的参数(JDK 1.7)

(1)初始容量(initialCapacity)  16

(2)扩容极限 1<<30 也就是231次方

(3)容量必须是2n次方,如果初始化时的参数不满足,会自动round-up

(4)散列函数 对于一个哈希表来说,散列函数决定了访问的效率的高低


2.Hashmap源码分析

2.1插入

ublic V put(K key, V value) {        if (table == EMPTY_TABLE) {            //如果表为空就初始化表            inflateTable(threshold);        }        if (key == null)            //#细节1 如果key为null            return putForNullKey(value);                //key不为空时        //先计算key的hash值,JDK1.7的源码的hash函数比较繁琐,建议看1.8的        //细节2        int hash = hash(key);        //计算出要放在table数组中的位置i        int i = indexFor(hash, table.length);        //如果在位置i的链中找到这个key就覆盖        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))) {                V oldValue = e.value;                e.value = value;                //#细节3                e.recordAccess(this);                return oldValue;            }        }        //        modCount++;        addEntry(hash, key, value, i);        return null;}

#细节1 关于null key的处理

private V putForNullKey(V value) { //在table数组头寻找key为null的Entry //为什么要在table[0]查找?因为在hash()方法中key为null的值的hash为0     for (Entry<K,V> e = table[0]; e != null; e = e.next) { //如果找到的话,就用新的value值去覆盖旧的value值,然后返回新的value值     if (e.key == null) {         V oldValue = e.value;         e.value = value;         e.recordAccess(this);         return oldValue;      }  }  modCount++;  //如果没找到的话,就新建一个Entry  //void addEntry(int hash, K key, V value, int bucketIndex)  addEntry(0, null, value, 0);  return null;}

#细节2 hash()散列函数

建议看https://www.zhihu.com/question/20733617里的解析,讲得很好,是JDK1.8


#细节3 recordAccess

/** * This method is invoked whenever the value in an entry is * overwritten by an invocation of put(k,v) for a key k that's already * in the HashMap. *///这个方法是为了重写来实现在插入值被覆盖时执行某些算法的,LinkedHashMap可以通过重写这个函数来实现LRU,同样的也有重写recordRemoval()来实现删除某个key时执行某些算法void recordAccess(HashMap<K,V> m) {}

2.2删除

public V remove(Object key) {        Entry<K,V> e = removeEntryForKey(key);        return (e == null ? null : e.value); }

remove的实现是通过removeEntryForKey来实现的

final Entry<K,V> removeEntryForKey(Object key) {        //容量为0时返回null        if (size == 0) {            return null;        }        //计算这个key的hash值来定位这个key放在table数组中的位置        int hash = (key == null) ? 0 : hash(key);        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;            //如果根据hash值找到了key            if (e.hash == hash &&                ((k = e.key) == key || (key != null && key.equals(k))))//如果相比较的两个key的指向的物理地址相同或者逻辑含义相同,很细节{                modCount++;                size--;                if (prev == e)                    table[i] = next;                else                    prev.next = next;                e.recordRemoval(this);                return e;            }            //如果没找到的话            prev = e;            e = next;        }        //如果一直没找到,最后e会为null        return e;    }

2.3扩容

void transfer(Entry[] newTable, boolean rehash) {        int newCapacity = newTable.length;        //对每个key取hash值,然后通过indexFor方法来决定放在哪一位        //具体来说就是(以JDK1.8的散列函数为例)        //假如原来的容量是16,indexFor时要看hash值最后4位,新的容量是32,indexFor                                                       时要看hash值最后5位,如果多出来的这一位为0,就放在原先的桶里,如果多           出来的这一位为1,就放在oldIndex+oldCapacity里,也就是oldIndex+16        for (Entry<K,V> e : table) {            while(null != e) {                Entry<K,V> next = e.next;                if (rehash) {                    e.hash = null == e.key ? 0 : hash(e.key);                }                int i = indexFor(e.hash, newCapacity);                e.next = newTable[i];                newTable[i] = e;                e = next;            }        }}

3.HashMap JDK1.8JDK1.7的对比

(1)新增了红黑树,如果table[i]链的长度大于TREEIFY_THRESHOLD(默认为8),就会把这个链转化为一个TreeBin节点,里面是一个红黑树。如果扩容时新链的长度小于UNTREEIFY_THRESHOLD(默认为6),就把它还原成一个链表。

(2)散列函数的效率上有提升,具体见https://www.zhihu.com/question/20733617的分析



0 0
原创粉丝点击