HashMap原理

        hashmap毋庸置疑是面试的经常需要考的题目了,不知道你有没有跟我一样的疑惑,hash是干嘛的?为什么要使用hashcode?hash碰撞是什么玩意?下面是我从一些官网或者gpt以及理解的一些笔记。

概念

哈希表

         散列表(Hash Table),也被称为哈希表,是一种非常常见的数据结构,用于存储键值对。哈希表的主要思想是,通过哈希函数将键(Key)映射到数组的一个索引上,然后在该索引处存储对应的值(Value)


hash碰撞

        hash碰撞:在使用哈希函数将键(Key)映射到数组的一个索引上时,存在相同索引的情况,这种相同索引就被成为hash碰撞(本质就是通过hash算法来计算得到的hashcode会重复导致映射到同一个index),而解决hash碰撞就是使用链表,在相同的index基础上扩张链表。


hash算法

        哈希算法(Hash Algorithm)是一种将任意长度的二进制值映射为固定长度二进制值的算法。这个映射后的二进制值被称为哈希值,也被称为散列值或摘要。
    哈希算法在许多领域都有应用,包括数据加密、数字签名、散列函数等。常见的哈希算法有MD5、SHA系列、MurmurHash等。在使用哈希算法时,需要注意选择合适的算法,并采取适当的措施来防止哈希冲突和确保数据安全性。

异或运算符

        XOR是一个数学运算符,也被称为异或运算符,它的符号是"⊕"或"xor"或者"^"其运算法则是:当两个输入值不同时,输出为1;当两个输入值相同时,输出为0,例如:二进制0101^1011=1110,为什么介绍这个概念因为后续会在hashcode的计算是使用。
    

原理

        HashMap原理_第1张图片

        hashmap是一种key-value形式存储和访问的数据结构,其中key是唯一的,value可以是任意的,其特点是允许null为键和值,并且线程是不安全的。

 对比        

        JDK1.7及之前:节点被称为entry,底层数组加链表,使用头插法(可能会导致Infinite Loop可能出现无限循环)。
        JDK1.8及以后:节点被称为node,底层数组、链表(当链表数量小于7时转链表)和红黑树(当链表数量大于7时转红黑数),注意等于7是中间值(这个值是通过大量的实验和性能测试,得出的一个结果,符合大部分场景,说是单个hash槽内元素个数为8的概率小于百万分之一,所以将7作为分水岭),使用尾部插入法。

结构


        接下来我们put一个值看下发生了些什么,例如我们put("key1","value1");put插入数据时,map会根据key的hash值以及数组长度去计算一个index(index=(数组长度-1)&hashcode())来存到索引为index所在的数据中,由于计算时可能发生hash碰撞的缘故会导致index是相同的,所以这时会在相同index下衍生链表,当链表>7时则会转为红黑树(为了增加查询效率)。

例如下图:

        HashMap原理_第2张图片

扩容

        我们都知道数组是固定长度大小的内存空间,当数组达到一定的数据量后内存会满,这时就涉及到了数组的扩容,影响hash数组扩容的两个点:
        1、数组长度:默认数组长度16(为什么是16其实是因为index=(数组长度-1)&hashcode()当数组长度-1是等于15,对应二进制位1111,1111与任何二进制数都是其本身,尽可能地不影响离散算法本身,如果hash本身是均匀的,那么结果也就是均匀的,是就是为了hash的均匀分配),该值使用1<<4(左移4位即2的4次方)位运算符。位与运算比算数计算的效率高(这个很简单因为位运算符针对的是二进制,算数需要转为二进制在进行计算肯定会有时间的差异)
        2、离散因子:默认是0.75f,其实就是用来判断什么时候需要扩容的,比如有10个数据,当我们在存储第八个数据的时候就需要扩容了。
    扩容:
        1、创建一个新的数组,长度是原来的2倍。
        2、会重新遍历原数组,并将原数组重新计算index到新数组中,这里有个注意的点由于index在源码中是跟数组长度有关的,并且index=(数组长度-1)&hashcode()

你可能感兴趣的:(Java基础,java)