HashMap是JAVA语言中的Map接口的实现类之一,特点是插入慢、查询快,HashMap是JAVA中使用频率最高的映射(键值对)处理的数据类型。
HashMap内部默认为数组+链表(红黑树)的存储结构,数据结构如下:
数组中每个元素称之为一个桶(bucket),每个桶中默认使用链表的方式存储键值对。
关于性能的设计
1、 容量和加载因子是影响性能的重要因素
容量是哈希表中桶的数量,加载因子是表示哈希表中元素填满的程度,容量默认值为16,加载因子默认为0.75,也就是说当元素达到16*0.75=12时,容量就需要扩容了。
2什么是哈希冲突,链表与红黑树转换
当发生键值对存在hash冲突(不同key的hash值相同)时,落在同一桶的元素会越来越多。当链表长度大于8且容量大于64时(源码中的默认值),链表会转换为红黑树,另外,当同一个桶中元素长度小于6时会转回链表结构,应避免这种来回转换。
3扩容
hashmap每次扩容都是原来的2倍,主要原因是:一方面是为了让重新计算的索引只有两种情况,一种是索引落在原位置,另外一种是在原位置再移动2次幂的位置。另外一方面是尽量把数据散列分布均匀,减少rehash。
以上这些设计都是为了解决查询,插入,删除等操作时的性能的一个折中考虑。
使用建议
1) 构造hashmap实例时就设置初始容量,建议设置为已知元素个数/0.75f+1(参考阿里的编码规范),避免扩容引起的rehash。
2) 长期留在内存的HashMap,可以降低加载因子,目的是减少hash冲突,不过会造成内存浪费(通过空间换时间)。
3) HashMap是非线程安全的,多线程并发编程情况下,会出现死循环,应使用ConcurrentHashMap代替。