简单介绍:
HashMap是基于哈希表实现的Map接口实现类。这个实现提供所有的map相关的操作,map接口是以<key,value>的形式存储数据,就是双值存储(也叫键值对)。允许使用null的键和null的值(允许key和value的值为null),并且HashMap内部元素排列是无序的。
HashMap最基础实现方式:
数组+链表
源码分析:(JDK1.7)
继承关系:
Map<K,V>:存放双值,存储 key-value键值对,且 key部分不能重复
Cloneable:集合可以使用clone方法
Serializable:可序列化 表示LinkedList可以进行序列化操作。
常用方法(增删改查扩容等):
(1).put方法:
根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
(2).remove方法:
这个方法是根据Key值删除,删除是头一个节点。此外,还有一个clear方法
,可以将map清空。
(3).get/contains方法:
根据Key值可以查询到Value的值;
根据key值查询是否存在,返回true或者false;
根据Value查询是否存在,返回值是true或false;
(4).HashMap没有对应的修改方法,因为put插入方法会在插入相同key值的时候对已存在得key对应的Value值进行覆盖。
(5).hash算法:
通过扰动处理 加大哈希码低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性 & 均匀性,最终减少Hash冲突,让哈希码分布的更加均匀 从而避免出现哈希冲突。
(6).扩容方法:
当hashmap中的元素个数超过数组大小乘以loadFactor时,就把默认数组的大小(16)扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能。当hashmap中的元素越来越多的时候,碰撞的几率也就越来越高(因为数组的长度是固定的),所以为了提高查询的效率,就要对hashmap的数组进行扩容,数组扩容这个操作也会出现在ArrayList中,所以这是一个通用的操作,很多人对它的性能表示过怀疑,不过想想我们的“均摊”原理,就释然了,而在hashmap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去。
总结:
HashMap是个很好用的计数器,但是HashMap的存储结构比较浪费空间,另外HashMap是线程不安全的,在多线程put的情况下,有可能在容量超过填充因子时进行rehash,因为HashMap为了避免尾部遍历,在链表插入元素时使用头插法,多线程的情况下可能造成死循环。