hashMap原理

1.hashmap的底层数据结构
以key-value存储形式存在;线程不安全的。key、value都可以为null,储存无序
JDK1.8之前 HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决hash冲突(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在的
JDK1.8以后在解决哈希冲突时有了较大的变化,当链表的长度大于8(默认)并且当前数组的长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。在这之前不用红黑树得原因是因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡,反而会降低效率。

2.hashmap存储元素的过程
首先调用key对象的hashcode()方法,计算出hash值。然后用这个哈希值确定在数组中的位置,再把value值放进去,如果这个位置本来没放东西,就会直接放进去,当两个对象的hashCode相等时,会产生哈希碰撞,若key值内容相同则替换旧的value,不然连接到链表后面,链表长度超过阈值8就转换为红黑树存储,通过equals比较内容是否相同。
相同:则新的value覆盖之前的value
不相同:则将新的键值对添加到哈希表中
链表长度阈值超过8时且当前数组的长度>64,将链表转换为红黑树

3.hashMap 加载因子为什么0.75
如果空间利用率高,那么经过的哈希算法计算存储位置的时候,会发现很多存储位置已经有数据了(哈希冲突); 如 果为了避免发生哈希冲突,增大数组容量,就会导致空间利用率不高。
而加载因子就是表示Hash表中元素的填满程度。“
加载因子 = 填入表中的元素个数 / 散列表的长度
加载因子越大,填满的元素越多,空间利用率越高,但发生冲突的机会变大了;
加载因子越小,填满的元素越少,冲突发生的机会减小,但空间浪费了更多了,而且还会提高扩容rehash操作的次数。
冲突的机会越大,说明需要查找的数据还需要通过另一个途径查找,这样查找的成本就越高。因此,必须在“冲突的机会”与“空间利用率”之间,寻找一种平衡与折衷。
4.hashmap 为什么长度是2的n次方
如果数组长度不是2的n次幂,计算出的索引特别容易相同,及其容易发生hash碰撞,导致其余数组空间很大程度上并没有存储数据,链表或红黑树过长,效率降低。一般我们可能会想通过%求余来确定位置,这样也可以,只不过性能不如&运算。而且当n是2的幂次方时:hash&(length-1) == hash % length ,因此,HashMap容量为2次幂的原因,就是为了数据的均匀分布,减少hash冲突,毕竟hash冲突越大,代表数组中一个链的长度越大,这样的话会降低hashmap的性能,
如果创建HashMap对象时,输入的数组长度是10,不是2的幂,HashMap通过一通位移运算和或运算得到的肯定是2的幂次数,并且是离那个数最近的数字。

5为什么转换成红黑树的节点是8**
至于为什么阈值是8,8这个阈值定义在HashMap中,针对这个成员变量,在源码注释中只说明了8是bin(bin就是bucket桶)从链表转成树的阈值,一个bin中链表长度达到8个元素的概率为0.00000006,几乎是不可能事件。所以,之所以选择8,不是随便决定的,而是根据概率统计决定的,超过8的时候,概率已经非常小的,所以我们选择8这个数字

6.hashmap的构造函数哪些?
public HashMap(int initialCapacity, float loadFactor)
public HashMap(int initialCapacity)
public HashMap()
public HashMap(Map<? extends K, ? extends V> m)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值