HashMap实现原理(面试必背)

HashMap

HashMap以它极快的查询效率使它在Java语言开发中使用的十分广泛

实现原理

hashMap的底层实现原理是基于hash算法,利用数组+链表+红黑树(jdk1.8后加入红黑树)来实现的,另一个高级点的叫法是链表散列(也就是数组加链表),简单来讲,hashMap是由一个数组构成,而这个数组的每一个元素是Entry对象(key-value)或链表(链表保存的也是Entry对象)
在这里插入图片描述

为什么这样搞?

当然是为了效率!!!
hashMap在存储数据时,会通过(key.hash)%数组长度的方式来得到一个小于当前数组长度的数字,以这个数字为下标,找到数组对应位置,如果对应位置上没有元素,则构成一个Entry对象直接放到这个位置。
在这里插入图片描述

但是两个不一样的key很有可能计算出来的下标是一致的,这就导致hash冲突了,于是就引入了链表来解决这个问题,若找到对应位置时,发现已经有元素了,那么这时则会调用equals方法比较两个元素的key是否完全一致,是一致的,则更新已存在元素的value,不是一致的且不存在链表,则使用链表的方式将他们串联起来,存在链表就依次比对链表上的key,找到一致的就更新,比对结束还没有一致,那就加入他们(生成Entry对象串联在链表上)。快是很快的,但是HashMap也是线程不安全的。

为什么线程不安全

首先因为HashMap 的方法不是同步的,在上述的存储机制下,如果两个线程同时put一个key,两个key不一样但造成了Hash冲突,这两个数据会被放在数组同一个下标,而此时两个线程都没有equals到对方手中的key,结果就是有一个key会被覆盖,造成了数据的丢失,那么想要线程安全的使用HashMap就用这三个,这篇文章只记录HashMap
Hashtable
Sysnchronized Map
ConcurrentHashMap
详见 >>>>> ConcurrentHashMap实现原理(简单易懂)

HashMap的扩容机制

由于数据中的元素越来越多,导致Hash冲突越来越频繁,影响查询效率,所以要进行扩容,扩容时,需要将所有元素放到新的数组中,由于数组长度的变化(元素下标位置的计算依赖数组长度),则需要重新计算所有元素key的HashCode,将元素按照新的结果存放在新数组,这个操作是非常耗时的,所以如果能估算Map的容量,最好给它一个默认初始值,避免进行多次扩容,HashMap底层的数组数组的初始长度是16,扩容因子是0.75,即数组中元素数量达到数组长度的75%就会自动扩容,而链表上的元素大于8个时,会将链表转化为红黑树提升查询效率
在这里插入图片描述

HashMap常用方法

1.put()方法和 get()方法

put(K key,V value) 向HashMap集合中添加元素(也称将键(key)/值(value)映射存放到HashMap集合中)
get(Object key) 返回指定键所映射的值,没有该key对应的值则返回 null
此外HashMap是支持null为key来存储数据的,但由于key的唯一性,也和普通key一样唯一存在

在这里插入图片描述
2.containsKey(key)方法,isEmpty () 方法,clear()方法

containsKey()会遍历map中所有元素的key,与传入的key通过equals方法进行比较,有相同的key则返回true,没有则返回false
isEmpty () 判断map中是否有数据,有数据则返回true,无数据则返回false
clear()没有返回值,清空map中所有元素!
在这里插入图片描述

HashMap的遍历方式

1.遍历key的方式

  1. 使用set集合来遍历map中的key,map自带.keySet()方法,来获取map中key的集合
    在这里插入图片描述
  2. 获取set集合后使用迭代器iterator
    在这里插入图片描述
    2.遍历entry对象
    1.使用map,entrySet()方法获取entry对象的集合,从而进行遍历
    在这里插入图片描述
    1.使用迭代器遍历
    在这里插入图片描述

HashMap在JDK1.7与JDK1.8的区别

1.jdk1.7底层数据结构是数组+链表,jdk1.8是数组+链表+红黑树(当链表长度大于8,转为红黑树)
2.链表数据的增加jdk1.7使用的是头插法,jdk1.8使用的是尾插法(原因是增加了红黑树),当1.8中的桶中元素处于链表的情况,遍历的同时最后如果没有匹配的,直接将节点添加到链表尾部;而1.7在遍历的同时没有添加数据,而是另外调用了addEntry()方法,将节点添加到链表头部
3.jdk1.7在插入数据之前扩容,而jdk1.8插入数据成功之后扩容

上一篇 >>>>> HashSet实现原理(面试必背)
下一篇 >>>>> ConcurrentHashMap实现原理(简单易懂)

That’s it;

相逢已是上上签,何须相思煮余年。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值