这一章节我们来介绍HashMap的工作原理。
1.HashMap的工作原理图
下图引用自:http://www.admin10000.com/document/3322.html
2.HashMap初始化的时候我们可以这样理解:一个数组,每一个位置存储的是一个链表,链表里面的每一个元素才是我们记录的元素
3.下面我们来看put的源码:
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); 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; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
a.当key为空的时候,通过putForNullKey方法,把元素放到最开始的位置。注意:HashMap是允许Key为空的。下面的代码就是证明:
package com.ray.ch15; import java.util.HashMap; public class Test { public static void main(String[] args) { HashMap<String, String> map = new HashMap<String, String>(); map.put(null, "1"); } }
b.当key不为空的时候,需要计算key的hashcode,因为hashCode()方法是继承Object,因此每一个key都有这样的方法。当然,我们也可以重写hashCode(),但是这里将出现一系列的问题,我们后面的章节再展开。
注意:其中有一个hash()方法,就是把Key的hashCode再一次hash,这样做主要是为了使这个hash码更加的平均分布,下面是hash的源码:
static int hash(int h) { // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
d.当计算完链表在table上面的位置,我们就需要遍历上面的元素,因此出现了for循环。
扩展(1):这里需要突出一下上面所说的table,table的源码:
/** * The table, resized as necessary. Length MUST Always be a power of two. */ transient Entry[] table;
这个table,就是我们上图的左边的Y轴上面的1,2,3,4.....它每一个位置上都是记录一个Entry的链表。
从注释可以看到,这个table是可变的,当Map的容量超过某一个界限,他就会触发resize方法,从新创建一个table,然后把就的数据copy一份到新的里面去。下面是resize的源码:
void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); }
/** * The load factor used when none specified in constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f;
4.综上所述,Map的put 的流程是:
(1)检查key是否为空
(2)计算key的hashcode和在table里面的index(位置)
(3)找到table上面的元素
(4)遍历链表,如果没有就put进去,有就更新
总结:这一章节我们主要通过put方法来介绍HashMap的工作原理。
这一章节就到这里,谢谢。
-----------------------------------
目录