先从构造函数讲起吧
HashMap有很多个构造函数,不过我们比较常用的是不带参数的默认构造函数,其源代码如下:
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
事实上,HashMap的所有键值对被存放在一个Entry数组中(变量table),DEFAULT_INITIAL_CAPACITY(为16)即是默认的Entry数组长度的初始值,当然我们也可以自定义entry数组的长度,但是长度必须为2的n次方,为什么要如此,下面会讲解到。
Entry数组每一个索引处都可以存放一个Entry链(通过下面Entry的构造函数可以发现Entry对象可以指明它的下一个对象,所以多个Entry对象可以以Entry链的形式存在)
Entry类的构造函数如下:
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
每个存入HashMap的键值对都会以Entry对象的形式储存,Entry类除了拥有key和value变量外,还有两个重要的变量:
next指明了下一个Entry对象
hash是该Entry对象的哈希值(Hash码)
HashMap在存入键值对时首先会根据key的hashCode() 返回值来计算 Hash 码,然后通过该Hash码计算出这个这个键值对要放在数组的哪个索引处,
如果该索引处还没有存放entry对象则用要存入的键值对新建一个Entry对象并将此对象存放于这个索引处,并将next变量赋为null;
如果该索引已经存在entry链,则遍历该entry链,如果entry链中含有key和要存入的key相等的entry对象,则将该对象的value值替换成我们要存入的value;
如果该索引已经存在entry链,且entry链中没有key和要存入的key相等的entry对象,则用要存入的键值对新建一个entry对象,然后