HashMap 分为 hash和Map
哈希算法 是一类算法。
哈希表 (hashtable) 是一种数据结构
Map是映射 是一种 把 Key 映射到value 的无序集合
HashMap 是 java中用哈希表这种数据结构实现的Map
hash算法 是这样一类算法
这类算法接受任意长度的二进制输入值,对输入值作计算,最终给出 固定长度的二进制输出值
hash算法不是某个固定的算法 它代表的是一类算法
hash算法是摘要算法,也就是说,从不同的输入中,通过一些计算取出来一段输出数据,值可以用以区分输入数据
MD5就是一种不可逆的摘要算法
消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,目前可以被解密逆向的只有CRC32算法,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。
hash算法的应用场景
- 信息安全领域 。 hash算法作为摘要算法对文件进行加密,得到文件的摘要 任何下载的文件副本只要和官方给出的“数字指纹”一致,那么就是未经篡改的 例如著名的MD5
- 数据结构领域 使用hash函数实现的 hash表数据结构,这种结构可以实现对数据的快速存取
hash表
在线性表 树 这些结构中 记录在结构中的相对位置是随机的 和记录的关键字之间不存在确定的关系,字查找中需要进行和关键字的比较,查找的效率依赖于查找过程中所进行的比较次数。
hash表 理想情况下希望不经过任何的比较 一次存取便能得到所查记录,那就必须在记录存储位置和它的关键字之间建立一个确定的关系为hash函数,按这个方法建立的表称为hash表
HashMap是基于hash表的Map接口的实现
HashMap在jdk1.7的底层实现是由 数组+链表
1.数组
1.数组是相同数据类型的集合
2.数组中的元素具有先后顺序,它们在内存中按照这个先后顺序存放在一起
3.数组中的元素用数组的名字和它在数组中的下标来表示。
4.数组下标必须是整数,下标可以是常量 变量 表达式
2.单向链表
单向链表是链表的一种,它由节点组成,每个节点都包含下一个节点的指针
特点
- 新增删除方便 不像线性结构那样移动剩下的数据
- 查询慢 需要通过循环或者递归访问到任意数据
- 只能从头到位的遍历
红黑树
红黑树是一种特定类型的二叉树,也是一种平衡二叉查找树的变体,它的左右子树的高度差有可能大于 1 每一颗红黑树都是一颗二叉排序树,
特点
- 每个节点只能是红色和黑色
- 根节点必须是黑色
- 红节点的叶子节点必须是黑色
- 从任意节点到其每个叶子节点所在路径包含相同数目的黑色节点
HashMap特性
- 实现快速存储键值对,允许为null key值不可重复,若key值重复则覆盖
- 线程不安全
- 底层是Hash表 不保证有顺序
HashMap put原理
1.当我们给put() 方法传递键和值时,先对键做一个hashcode() 获取hash值 得到在bucket数组中位置,来存储entry对象
2.如果有相同数据则覆盖
3.先判断是否为树节点, 执行树的插入
4.否则 进行链表的插入 循环遍历到链表中某个节点为空,尾插法进行插入,插入之后判断链表个数是否到达红黑树的阀值8,将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树),以减少搜索时间,也可以遍历到有节点于插入元素的hash值和内容相同进行覆盖。
get 操作
计算key的hash值 计算下标获取在数组中的位置,如果在桶的首位就返回,否则就在树中或者链表中遍历查找
HashMap 扩容机制
扩容需要重新分配一个新数组,新数组是老数组的二倍长,然后遍历整个老数组 把所有的元素重新挨个hash分配到新结构中。
. HashMap默认初始化长度为16,并且每次自动扩展或者是手动初始化容量时,为什么必须是2的次幂?
- 为了数据的均匀分布,减少哈希碰撞。因为确定数组位置是用的位运算,若数据不是2的次幂则会增加哈希碰撞的次数和浪费数组空间。
- 输入数据若不是2的幂,HashMap通过一通位移运算和或运算得到的肯定是2的幂次数,并且是离那个数最近的数字
X % 2^n = X & (2^n – 1) 该方法主要是将hash生成的整型转换成链表数组中的下标。
return hash & (length-1);只要保证length的长度是2^n 的话,就可以实现取模运算了。
因为位运算直接对内存数据进行操作,不需要转成十进制,所以位运算要比取模运算的效率更高,所以HashMap在计算元素要存放在数组中的index的时候,使用位运算代替了取模运算。之所以可以做等价代替,前提是要求HashMap的容量一定要是2^n 。