HashMap原理简单认识

1. hashMap简单认识

优点:hashMap的存储方式是键值对(键可以包括null),查询速度存储方便存储数量最大为十几亿

缺点:主要是线程不安全,容易在hashmap扩容时形成死循环

2.hashMap从源码角度简单认识

jdk1.7 使用的数组 + 链表

jdk1.8 使用的数组 + 链表 + 红黑树

分析为什么使用数组 + 链表 + 红黑树:

数组:主要是方便查找,且在内存中是连续的。

链表:主要是方便插入,删除,然而hashMap把两个者有点结合在一起。

红黑树:主要是jdk1.8为了对链表进行优化时,增加的数据结构。那么在它们如何使用的呢? ,可以从put()函数中看出

hashmap重要参数
loadFactor 负载因子,默认值75%
threshold 临界值,超过临界值需要重新分配
modCount 统计删除和修改的次数
Entry 实体类,主要有四个参数组成,分别是key,hash,value,next

hashmap的构造函数

    1.无参构造

     

扫描二维码关注公众号,回复: 3844883 查看本文章

    2.有参构造

    

    

    分析hashmap的构造函数:

  通过在平时项目观察发现,大部分人都会使用无参的构造函数,因为会有初始值16,那么问题来了,如果我们存储数量大于16  呢,看过源码的人当然会说,需要进行扩容操作,可是数据量比较大的时候是不是申请很多内存空间,把一个数组里面的数据重新放到另一个数组里面去,这样可能比较消耗时间和内存,如果在多线程情况下,是不是容易出现数据问题,我个人观点,提前指定所需要的空间,那么有人会说,我可以知道需要申请多少空间,如果盲目申请内存是不是也会产生浪费,这样的观点是没有错的,但是我这里强调的是,在你大概知道需要多少数据量,应指定所需要申请的空间。

hashmap里面的put操作

addEntry函数:

createEntry:

putForNullKey函数:

hashMap里面put方法:

1.  首先初始化数组

2.  判断键是不是null,如果是null,用putForNullKey()来处理

3. 计算出哈希值

4. 用哈希值和数组长度进行indexFor()运算;得到下标i;

5. 通过下标i在数组里面找到对应的实体类,比较实体类里面hash值和key的==和equals方法,都相等的话,说明是要找的value

否则话,进行增加实体类

6. 在增加实体类时,都会进行判断,是否超过threshold值,如果超过就把原来数组的大小变为2倍。

分析put方法:

可以从源码和上述过程中,可以看出,在进行put操作时,首先会进行哈希值进行比较,然后在比较key的==和equal方法,那么在什么时候使用equal方法呢?,其实涉及到一个哈希冲突的问题,就是hashcode可能存在冲突,最后会和buckIndex的值一样,在这一种情况下,会调用equal方法,因为equal是Object方法,它直接比较的是内存大小。

hashmap里面的put操作通过hashcode值可以存放数据。当不同对象的哈希值相同时,会通过单链表的方式解决,将新元素插入表头,它的next指向原来的元素。(为什么插入表头不插入表尾,正在研究)

分析put方法的线程不安全:

hashmap很容易在put操作时,形成死循环。

分析死循环形成的原因:

1. 从上述源码中,可以看出死循环的原因主要是因为在进行扩容操作所造成的。

2. 首先把原来的大小变为2倍。

3. 遍历原来的数组

4. 因为是单链表,所以要保存下一个节点, Entry<k,v> next = e.next;

5. 因为e要插入表头,并且需要e指向链表的第一个元素,所以需要把e.next = newTable[i];

6. 然后让e变为数组的头指针。newTable[i] = e;

其实上述过程实际是单向链表的反转,在形成死循环时,主要是在第4 ,5 ,6步。

3.hashmap所涉及到的数据结构

  1. 链表

  2. 哈希运算

  3. 红黑树(jdk1.8自己正在研究中)

猜你喜欢

转载自blog.csdn.net/weixin_41629878/article/details/82937970