下面来看看get(Object key)方法的流程以及源码
从上面源码中可以看出:当系统决定存储 HashMap 中的 key-value 对时,是没有考虑 Entry 中的value的,仅仅只是根据key 来计算并决定每个Entry 的存储位置。这也说明了前面的结论:我们完全可以把Map集合中的value 当成key的附属,当系统决定了key 的存储位置之后,value 随之保存在那里即可。
int hash = hash(key.hashCode());这句来调用的上面的方法,可以看到hash(int h)方法里面纯粹的数学计算。对于给的对象,
hashCode()的值是相同的,那么算出的hash码也会是相同的。
接下来调用了此方法
通过h &
(table.length -1) 来得到该对象的保存位置,通过前面的定义可以知道,HashMap 底层数组的长度总是2的n次方,经过N次推算可以得出hash值与偶数与,得到的相同的值的几率比奇数大,如果相同的值多了,数据便会分配到相同的数组的位置上,链表中的值就多了,从链表中查询效率也就比较低了。
而hash值与奇数与,得到相同的值的几率低,便会分配不同的数组的值,查询只需要一次就好,效率相对来说也就比较高。
下面给出例子
一个哈希值是8,二进制是1000,一个哈希值是9,二进制是1001。和1111(奇数)与运算后,分别还是1000和1001,它们被分配在了数组的不同位置,这样,哈希的分布非常均匀。
再和1110(偶数)与,分别得到的值是1000和1000,得到了相同的值,哈希值8和9的元素多被存储在数组同一个位置的链表中。链表中的值越多,操作时对链表循环越多,效率也就越低了。所以,一定要哈希均匀分布,尽量减少哈希冲突,减少了哈希冲突,就减少了链表循环,就提高了效率。
下面这张图显示了HashMap的存储方式,数组+链表。
下面来看看put(K key, V value)方法,了解整个流程及源码分析
如果数据大小是固定的,那么最好给HashMap设定一个合理的容量值。不然不停的扩容,不停的给所有的元素重新哈希,那效率就惨了。
HashMap就到这了,主要的几个方法都简略的分析了下,把HashMap的结构弄清楚了,其余的方法步骤都差不多。
源码中可以看到HashMap不是同步的