学过Java的朋友都知道,HashMap是众多集合之一,非常重要,是一个键值对的集合。下面我们来说一说HashMap的底层实现原理。
ArrayList是由动态数组实现,LinkedList是由链表实现,而HashMap是这两个是结合体,他是有线性链表实现的。
之所以叫它线性链表也是因为是由数组和链表共同组成
线性链表
Entry就是每一个存入集合中的数据,每个Entry都是一个链表节点,这个节点中包含着一个键key,一个值value、只想下一节点的指针next和这个键所对应的哈希值。
- 桶的概念
在HashMap集合中,有一个桶的概念,这个桶的概念就是数组中每一个单位,每一个元素。例如arr[0]、arr[n]…..这些都可已成为桶。我们一直再说HashMap,这个哈希就体现在这个地方,这个键值对存在那个桶里和哈希值有很大的关系,得到桶的下标主要有两种方式,一种是key%n求得的余数则为桶的下标,另有一种的key&n,相与结果位桶的下标。这里的n指的是当时数组的长度,默认为初始长度为16。
- 插入方式
当有键值对存进来后,会先计算它应该在的桶,得到这个位置后,会放在里面。如果为空,则就放在第一个位置,但是当这个桶中已经有了一个Entry后,就会把新来的键值对插在前面,这种方式叫做头插法。
- key为空时
在HashMap中是允许key为null的,当key为null时为默认存放在下标为0的桶中。
- 扩容
随着存入的数据越来越多,每个桶中的来年表也会越来越长。链表的一个特点就是索引查找的的效率非常低这就导致了HashMap的效率也会变低,所以不应该在链表上存入大量数据,这时就需要随集合扩容。
在HashMap中有一个变量叫负载因子,他控制着集合何时需要扩容。负载因子的默认值为0.75,当size>(16*0.75)时就需要扩容了长度为默认长度的两倍,扩容结束后重新计算所有数据的桶,重新归位。
- 链表转红黑树
从jdk1.8开始,一个桶的长度大于8时链表将会转换成红黑树。