HashMap源码学习

来源:互联网 发布:新开淘宝网店卖什么好 编辑:程序博客网 时间:2024/05/22 10:51
  1. Lru的意思是先淘汰时间最远的哪一个,LFU则淘汰使用频率最小的哪一个。
  2. Hashmap

static int indexFor(int h, int length) {
return h & (length-1);
}
相当于%但length要是2的幂。

  • hashCode()用来确定对象在hashmap中的位置,函数返回一个整数,如果a.equals(b)a.hashCode()==b.hashCode()这两个函数一个用来确定对象是否相等,一个在hashMap中区分元素。hashCode()equals()的默认实现相似是内存地址。
for (Entry<K,V> e = table[0]; e != null; e = e.next) {                if (e.key == null) {                    V oldValue = e.value;                    e.value = value;                    e.recordAccess(this);                    return oldValue;                }        这个table[0]位置不光存了key==null的值,别的key也可能hash到这个位置
 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);                }            }        }     - 重新计算每个元素在表中的位置因为hash()%length中的length发生了变化并不是只要将table[i]中的一串列表直接移到newTable[i]中就行了。 - table[i]中是单链表以null结尾
final Entry<K,V> removeMapping(Object o) {            if (!(o instanceof Map.Entry))                return null;            Map.Entry<K,V> entry = (Map.Entry<K,V>) o;            Object key = entry.getKey();            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;            // 删除链表中的“键值对e”            // 本质是“删除单向链表中的节点”            while (e != null) {                Entry<K,V> next = e.next;                if (e.hash == hash && e.equals(entry)) {                    modCount++;                    size--;                    if (prev == e)                        table[i] = next;                    else                       prev.next = next;                    e.recordRemoval(this);                    return e;                }                prev = e;                e = next;            }            return e;        }      这个函数要是在双链表的实现中就可以直接删除了不用再找了。
  • 快速失败 fast-fail防止别的线程改变了表的结构
 final Entry<K,V> nextEntry() {                if (modCount != expectedModCount)                    throw new ConcurrentModificationException();                Entry<K,V> e = next;                if (e == null)                    throw new NoSuchElementException();                // 注意!!!                // 一个Entry就是一个单向链表                // 若该Entry的下一个节点不为空,就将next指向下一个节点;                // 否则,将next指向下一个链表(也是下一个Entry)的不为null的节点。                if ((next = e.next) == null) {                    Entry[] t = table;                    while (index < t.length && (next = t[index++]) == null)                        ;                }                current = e;                return e;            }    始终保持next为下一个,那么获取下一个就是返回next,next跟新为next的下一个。hasNext()就是检测next是否为null这种设计主要是为了hasNext();
  • 迭代器定义在hashMap内部他的构造函数为private所以只能有hashMap调用,迭代器由于是hashMap的内部类,可以之间操纵hashMap的内部结构,而next()方法由于生命为public可以被外部调用。

3、HashMap共有四个构造方法。构造方法中提到了两个很重要的参数:初始容量和加载因子。这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中槽的数量(即哈希数组的长度),初始容量是创建哈希表时的容量(从构造函数中可以看出,如果不指明,则默认为16),加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 resize 操作(即扩容)。
文/Maat红飞(简书作者)
原文链接:http://www.jianshu.com/p/fc9e37ee2afd
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
4、HashMap中key和value都允许为null。
扩容是一个相当耗时的操作,因为它需要重新计算这些元素在新的数组中的位置并进行复制处理。因此,我们在用HashMap的时,最好能提前预估下HashMap中元素的个数,这样有助于提高HashMap的性能。

如果hashmap中有重复key则第二次插入讲第一次的value覆盖

1 0
原创粉丝点击