一般来说啊,实现哈希表我们可以采用两种方法:
1、数组+链表
2、数组+二叉树
1、ArrayList扩容与HashMap扩容?(详细在博客收藏上)
Arraylist
简而言之,arraylist创建对象后,第一次添加数据进去时,底层会创建默认长度为满足10的数组,当长度满时,则会自动扩容,扩容为原来的数组1.5倍。
HashMap
关于链表转红黑树:在Java8之前是没有红黑树的实现的,在jdk1.8中加入了红黑树,就是当链表长度为8时会将链表转换为红黑树,为6时又会转换成链表,这样时提高了性能,也可以防止哈希碰撞攻击(为什么要转就是怕链表长了那些存储太繁杂)(具体看hashtable的两种存取方式)
transient Node<K,V>[] table;
看到了,这就是HashMap底层的那个数组,之前说了jdk1.8中数组中的每个元素叫做Node,所以这就是个Node数组。
第一次使用HashMap添加数据的时候底层会创建一个长度为16的默认Node数组。这里怎么扩容的呢?首先是达到一个条件之后会发生扩容,什么条件呢?就是这个负载因子,比如HashMap的容量是100,负载因子是0.75,乘以100就是75,所以当你增加第76个的时候就需要扩容了,那扩容又是怎么样步骤呢?首先是创建一个新的数组,容量是原来的二倍,为啥是2倍,想一想为啥容量是2的整数次幂,这里扩容为原来的2倍不正好符号这个规则嘛。
而且这个扩容也不是简单的把数组扩大,而是新创建一个数组是原来的2倍,然后把原数组的所有Entry(注意entry是键值対的一种叫法)都重新Hash一遍放到新的数组。
小白: 这个重新Hash一遍是啥意思啊?
回答: 因为数组扩大了,所以一般哈希函数也会有变化,这里的Hash也就是把之前的数据通过新的哈希函数计算出新的位置来存放。