转载自https://github.com/Snailclimb/JavaGuide (添加小部分笔记)感谢作者!
HashMap简介#
- HashMap用来存放键值对,基于哈希表的Map接口实现,是非线程安全的
- 可以存储null的key和value,但null作为键只能有一个
- JDK8之前,HashMap由数组和链表组成,链表是为了解决哈希冲突而存在;JDK8之后,当链表大于阈值(默认8),则会选择转为红黑树(当数组长度大于64则进行转换,否则只是扩容),以减少搜索时间
- HashMap默认初始化大小为16,每次扩容为原容量2倍,且总是使用2的幂作为哈希表的大小
底层数据结构分析#
JDK8之前,HashMap底层是数组和链表,即链表散列;通过key的hashCode,经过扰动函数,获得hash值,然后再通过(n-1) & hash 判断当前元素存放位置(n指的是数组长度),如果当前位置存在元素,就判断元素与要存入的元素的hash值以及key是否相同,相同则覆盖,否则通过拉链法解决

扰动函数,即hash(Object key)方法
//JDK1.8 static final int hash(Object key) { int h; // key.hashCode():返回散列值也就是hashcode // ^ :按位异或 // >>>:无符号右移,忽略符号位,空位都以0补齐 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }JDK1.7
//JDK1.7 , 则扰动了4次,性能较差 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); }
JDK1.8之后,当链表长度大于阈值(默认为 8)时,会首先调用
treeifyBin()方法。这个方法会根据 HashMap 数组来决定是否转换为红黑树。只有当数组长度大于或者等于 64 的情况下,才会执行转换红黑树操作,以减少搜索时间。否则,就是只是执行resize()方法对数组扩容。相关源码这里就不贴了,重点关注treeifyBin()方法即可!



而对于enum类型,


