HashMap
HashMap是无序的,HashMap在put的时候是根据key的hashcode进行hash然后放入对应的地方
1.HashMap的设计原理
HashMap设计思路:
-
Map是一种以键值对存储数据的容器,而HashMap则是借助了键值Key的hashcode值来组织存储,使得可以非常快速和高效地地根据键值key进行数据的存取。
-
对于键值对,HashMap内部会将其封装成一个对应的Entry对象,即Entry对象是键值对的组织形式;
-
对于每个对象而言,JVM都会为其生成一个hashcode值。HashMap在存储键值对Entry的时候,会根据Key的hashcode值,以某种映射关系,决定应当将这对键值对Entry存储在HashMap中的什么位置上;
-
当通过Key值取数据的时候,然后根据Key值的hashcode和内部映射条件,直接定位到Key对应的Value值存放在什么位置,可以非常高效地将Value值取出。
2.HashMap的数据结构:
(数据结构有链表和数组两种实现对数据的存储)
数组:
数组存储区间是连续的,占用内存严重,故空间复杂度很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;
空间复杂度:指的是执行算法所需要的内存空间
时间复杂度:执行算法所需要的计算工作量
链表:
链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。
哈希表:
那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。
哈希表((Hash table)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。 哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法—— 拉链法,我们可以理解为“链表的数组” ,如图:
从上图我们可以发现哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。
那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,
也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,
12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。
HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。
这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。
首先HashMap里面实现一个静态内部类Entry,其重要的属性有 key , value, next,从属性key,value我们就能很明显的看 出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是 Entry[],Map里面的内容都保存在Entry[]里面。
HashMap的存储实现
既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现:
// 存储时:
int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
int index = hash % Entry[].length;
Entry[index] = value;
// 取值时:
int hash = key.hashCode();
int index = hash % Entry[].length;
return Entry[index];
解决hash冲突的办法
开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
再哈希法
链地址法 (Java中hashmap的解决办法就是采用的链地址法。)
建立一个公共溢出区
--------------------- 本文来自 AlphaWang 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/vking_wang/article/details/14166593?utm_source=copy