HashMap
HashMap简述
一种基于哈希表实现的数据类型,
在jdk1.8之前数据结构由数组+链表
在jdk1.8之后数据结构由数组+链表+红黑树。
数据安全,初始化,作用,数据顺序等
继承关系图
数据结构
在java中使用比较广泛用来存储相同数据类型的键值对的集合之一。在数据存储的过程中允许一个key或value为null,非线程安全且无序的集合。
在jdk1.8后,底层实现是基于数组,链表和红黑树组成的
优点: 提供高效的,删除 插入和查找操作,
缺点:线程不安全,无序
linkedHashMap 有序的HahsMap
concurrentHashMap 线程安全,通过分段锁,本质就是将整个hash表分为多个小的hash表(段),每段都能独立读写,每个段内部都是类似hashmap的实现方式,从而达到并发的效果。
是否线程安全 --否
否,在多线程环境下,数据是不同步的,如果两个线程同时操作会出现数据问题,
线程安全的map有 concurrentHashMap ,分段锁
简述new HashMap() 的流程
通过源码查看 new 的过程中,做了哪些操作,只是做了简单的初始化
通过Hashmap的无参构造初始化创建一个长度16,装载因子为0.75的map
package com.ruoyi.project.system;
import java.util.HashMap;
public class NewHashMapTest {
public static void main(String[] args) {
//
HashMap<String,String> test = new HashMap();
//test.put("a","b");
}
}
动态扩容
在put数据时 会对表的长度进行判断,当元素的数量大于装载因子乘数组的长度时,会进行扩容操作,每次扩容是原来的一倍,核心方法是resize方法。
resize方法主要是新建了一个扩容后的map,然后将原数据重新hash进集合里面,过程中数据的位置可能会有所改变,如果原来的位置已有参数,当前数据将放到链表的末尾,当链表的长度达到阈值(默认8)时,将转为红黑树。
装载因子为什么是0.75?
将空间和时间进行最合理最大程度的利用和优化。
put 流程
map.put(key,value);
例:
- 首先获取key的hash值
- 通过hash值扰动函数让hash更散列,其目的是为了让hash分步更均匀
- 判断集合是否为空,为空则分配空间,
- 构造node对象
- 不为空则查看是否需要扩容,是否需要转红黑树
- 通过路由算法,计算出对象存储位置计算,公式:(table.length-1) & node.hash
- 将对象存入对应的位置中
hash碰撞(冲突)
什么是hash碰撞
当A B两个不同的数据通过hash函数计算之后得到相同的值,导致B也需要放到A所在的位置,这就导致了冲突。
解决办法–四种
-
开放定址法
当key的hash地址p出现碰撞时,基于p再hash的到p1,如果p1仍然冲突则继续基于p,再hash ,直到得到一个不冲突的地址,将对应的数据存入。
-
再hash(双hash)
在发生冲突时,使用第二个,第三个 hash函数进行计算直到不再冲突为止
-
链地址法(hashMap默认)
将同一个散列槽(数组的每一个槽)中的所有数据放到一个链表中,node对象有一个next对象,通过next连接起来形成链表。
-
建立公共溢出区
将hash表分为基本表和溢出表,把所有与基本表冲突的数据放入溢出区。
扰动函数
本质是为了让hashcode分布的更均匀
扰动函数————(h = key.hashCode()) ^ (h >>> 16) 表示:
将key的哈希code一分为二。其中:
【高半区16位】数据不变。
【低半区16位】数据与高半区16位数据进行异或操作,以此来加大低位的随机性。
- 注意:如果key的哈希code小于等于16位,那么是没有任何影响的。只有大于16位,才会触发扰动函数的执行效果。