• Map集合之HashMap细说


            最近在看面试题,看到了hashmap相关的知识,面试中问的也挺多的,然后我这里记录下来,供大家学习。

    Hashmap为什么线程不安全

    • jdk 1.7中,在扩容的时候因为使用头插法导致链表需要倒转,从而可能出现循环链表问题或者数据丢失的问题

    • jdk 1.8中,在put方法中,假设A,B两个线程都插入相同的值到同一个下标,这个下标对应的值此时为null,假设线程A进行方法后挂起,而线程B顺利执行,此时该下标对应的值为B插入的值,然后A线程获得时间轮,此时线程A不再进行hash判断了,直接进行插入,就会导致覆盖了原来B插入到该下标的值

    HashMap类(底层为数组+链表+红黑树)

    扩容机制

            在java8以后,满足扩容机制的只需要笑傲一个条件即可,即当加入的新的数据和其他数据大于或者等于阈值就会发生扩容,且这种扩容形式也是在先插入新值后,再进行扩容。

            在java7中,每个节点存放一个Entry,每个Entry后面跟着一个链表,链表的每个节点存放一个Entry,这个Entry上保存有相应的key/Value,且存放着下一个节点的地址;在java8之后,因为引入了红黑树,所以把Entry改成了Node,其他的存放的内容都和Entry上面存放的一样。

            但是,在java8后虽然底层结构变成了数组+链表+红黑树,但是不一定会用到红黑树,只有当总的数据量大于64或者链表长度大于8的时候会将链表转换为红黑树。

    扩容满足的条件(什么时候扩容)

    在java7中,扩容需要满足以下两个条件(任意一个满足都会发生扩容)

    • 存放当前元素前,数据个数大于等于阈值

    • 存放当前元素时发生hash冲突

    在java8后,扩容只需要满足--》存放当前元素后,数据量大于等于阈值,且扩容是在插入新数据后进行扩容

    为什么在JDK 1.8后hashmap底层要添加红黑树

            当hash冲突过多的时候,数据插入到链表后面就会越来越多,就会导致链表链化严重,对于CRUD这些操作会造成较高的复杂度(O(n)),所以为了解决这一问题,在java8后使用红黑树来处理这种链化的情况。

    hash冲突怎么解决

            hash冲突表示的是当插入一个新值的时候通过hash函数计算出的下标值已经存入得对应数据,这个时候再插入一个值的时候就会出现hash冲突。

    开放地址法
    线性探测

            根据hash函数计算下标值,如果当前下标已经有值存在,那就去判断下一个下标是否存值,通过这样的方式来解决hash冲突,但是这样的方式可能会引起聚集,即连续找了多次下标都是有值的情况,这样会在后续的操作中增加复杂度。

    二次探测

    即根据hash下标的二次方进行探测(1,4,9.......),这样的做法可以减少聚集的问题

    双重散列

            如果当前通过hash散列函数计算出的下标已经存入了值,那就在用另外的hash散列函数再次进行计算

    链地址法

            每一个hash桶后面都会跟着一个链表,当通过hash函数找到对应桶,如果当前值对应下标在链表中已经存入了值,那么就会将该值放在链表末尾然后进行存储。

    再哈希

           再哈希是指当前的哈希函数计算出来的下标值已经被占用,这时就会使用一个新的哈希函数来进行再次计算。

    双重散列和再哈希的区别

            双重散列和再哈希都是需要使用多个hash函数来解决hash冲突,但是对于双重散列而言,每一次的hash函数都是新的hash函数,不会根据前一个hash函数计算出来的下标值为基础进行计算,而再哈希的每一个hash函数会根据前一个hash函数计算出来的下标值为基础进行计算,这样对于下一次计算出来的下标肯定不会和前一个hash函数计算出来的下标相重合。

    hashmap和hashtable的区别

    • hashmap是线程不安全的,而hashtable是线程安全的

    • hashmap可以存储null键和null值,hashtable不能存储null键和null值

    • hashmap在jdk1.8之后底层结构为数组+链表+红黑树,hashtable底层数据结构为数组+链表

    以上为自己学习过程中列出来的知识点,当然还存在很多不足,各位有补充的可以在评论区进行留言我们共同学习~

  • 相关阅读:
    CCIE理论-IPSec的主模式和野蛮模式的区别
    SQL改写系列九:外连接转内连接的常见场景与错误
    超越时间与人力的软件开发智慧:《人月神话》
    新版TCGAbiolinks包学习02:提取新版TCGA表达矩阵(tpm/count/fpkm)
    人工智能:科技魔法赋予生活新意
    补坑:Java的字符串String类(1)
    本地Linux服务器使用docker搭建DashDot并实现公网实时监测服务器信息
    如何使用GPT?初学者的指南
    泛型的类型擦除后,fastjson反序列化时如何还原?
    Apollo安装
  • 原文地址:https://blog.csdn.net/qq_71416673/article/details/139887321