-
jdk1.7:由数组 + 链表组成,数组是主体,链表主要是为了解决哈希冲突(即通过key计算的数组索引值相同)而存在的(“拉链法”解决冲突)。
-
jdk1.8+:由数组 + 链表+红黑树组成,在解决哈希冲突时有了较大的变化,当链表长度大于阈值(红黑树的边界值,默认为8),并且当前数组长度大于64时,此索引位置上数据存储结构转变为红黑树。 补充:链表转换成红黑树之前,即使阈值大于8,但数组长度小于64时,并不会将链表变为红黑树,而是对数组进行扩容。 目的是:当数组较小情况下,尽量避开红黑树结构。因为数组较小情况下,变为红黑树结构,反而会降低效率(红黑树需要逬行左旋,右旋,变色这些操作来保持平衡)。同时数组长度小于64时,搜索时间相对要快些。所以结上所述为了提高性能,底层阈值大于8并且数组长度大于64时,链表才转换为红黑树,具体可以参考 treeifyBin() 方法。
边界值为什么是6和8?因为当链表的数目超过7时,链表的查询效率不如红黑树,当红黑树的节点数目小于7时,查询效率不如链表。这里取了7的+-1的边界判断
当然虽然增了红黑树作为底层数据结构,结构变得复杂了,但是阈值大于8并且数组长度大于64时,链表转换为红黑树时,效率也变的更高效。
特性:
- 1、HashMap的存取是没有顺序的
- 2、KV均允许为NULL
- 3、多线程情况下该类安全,可以考虑用HashTable。
- 4、JDk8底层是数组 + 链表 + 红黑树,JDK7底层是数组 + 链表。
- 5、初始容量和装载因子是决定整个类性能的关键点,轻易不要动。
- 6、HashMap是懒汉式创建的,只有在你put数据时候才会build
- 7、单向链表转换为红黑树的时候会先变化为双向链表最终转换为红黑树,双向链表跟红黑树是共存的,切记。
- 8、对于传入的两个key,会强制性的判别出个高低,判别高低主要是为了决定向左还是向右。
- 9、链表转红黑树后会努力将红黑树的root节点和链表的头节点 跟table[i]节点融合成一个。
- 10、在删除的时候是先判断删除节点红黑树个数是否需要转链表,不转链表就跟RBT类似,找个合适的节点来填充已删除的节点。
- 11、红黑树的root节点不一定跟table[i]也就是链表的头节点是同一个哦,三者同步是靠MoveRootToFront实现的。而HashIterator.remove()会在调用removeNode的时候movable=false。