HashMap

一、HashMap的简介

HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

  • 存储结构:数组+链表,数组+红黑二叉树
  • key 和 value 都允许为 null,线程不安全

二、HashMap的原理

HashMap集合中,存储数据,实际上是一个Node类型的数组(JDK1.7是Entry类型),中间的每个元素又是一个链表,也就是我们所说的哈希表。
JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表中,但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8之后,哈希表存储采用数组+链表/红黑树实现。当链表长度超过阈值(8),先判断table的长度是否大于64,就转换为红黑树,这样大大减少了查询时间.如果小于64,就通过扩容的方式来解决,避免红黑树结构化。
简单的来说,哈希表是由数组+链表+红黑树实现的,如下图所示:

在这里插入图片描述

特点:

  1. 存取无序的
  2. 键和值位置都可以是null,但是键位置只能是一个null
  3. 键位置是唯一的,底层的数据结构控制键的
  4. jdk1.8前数据结构是: 数组 + 链表 ;jdk1.8之后是 :数组 + 链表 / 红黑树
  5. 阈值(边界值) > 8 并且数组长度大于64,才将链表转换为红黑树,变为红黑树的目的是为了高效的查询。

存储原理

  1. 它的底层会调用Key的hashCode()方法得出hash值。 ( Key --> hash值)
  2. 通过哈希表函数/哈希算法,将hash值转换成数组的下标. ( hash值 --> 数组下标 )
  3. 下标位置上如果没有任何元素,就新创建一个Node节点,并添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着key和链表上每个节点的key进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。

读取原理

  1. 先调用 key 的 hashCode() 方法得出哈希值,并通过哈希算法转换成数组的下标。 key --> hash值 --> 数组下标 )
  2. 通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。重点理解如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着参数 Key 和单向链表上的每一个节点的 Key 进行 equals,如果所有 equals 方法都返回 false,则 get 方法返回 null。如果其中一个节点的Key 和参数 Key 进行 equals 返回 true,那么此时该节点的 value 就是我们要找的 value 了, get方法最终返回这个要找的value。

在这里插入图片描述

三、HashMap的扩容机制

数组的容量是有限的,多次插入数据的话,到达一定数量就会进行扩容

扩容时机

当HashMap中的 元素个数超过数组长度loadFactor(负载因子) 时,就会进行数组扩容,loadFactor的默认值是0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中的元素个数超过16×0.75=12(这个值就是阈值)的时候,就把数组的大小扩展为2×16=32,即扩大一倍。然后重新计算每个元素在数组中的位置,而这是一个非常耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预知元素的个数能够有效的提高HashMap的性能。

四、红黑树结构

JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。
jdk8在哈希表中引入红黑树的原因只是为了查找效率更高

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值