码迷,mamicode.com
首页 > 其他好文 > 详细

hashMap 详细介绍

时间:2019-12-13 23:53:39      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:tree   fse   线性地址   hash冲突   容器   位置   offset   有一个   修改   

 

hashMap 源码 1192行。

一、HashMap概述

  HashMap基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

值得注意的是HashMap不是线程安全的,如果想要线程安全的HashMap,可以通过Collections类的静态方法synchronizedMap获得线程安全的HashMap。

 Map map = Collections.synchronizedMap(new HashMap());

二、HashMap的数据结构

  HashMap的底层主要是基于数组和链表来实现的

  HashMap中主要是通过key的hashCode来计算hash值的外加取余最终获取索引,而这个索引可以认定是一种地址,既而把相应的value存储在地址指向内容中。它通过把关键码值(key-value)映射到表中一个位置来访问记录,以加快查找的速度。

为什么又需要对得到的散列码(即hash值)求余呢?---上面的 indexFor(int h, int length)完成的功能

在底层是用数组来存储<key, value>的,而我们得到的散列码可能很大(事实上散列码的范围非常广)

而内存是有限的,不能分配为数组分配一块很大很大的空间,因此,存储<key, value>的数组空间相对较小。

从而需要把 所有的散列码都 “约束” 到这个有效的数组空间中。----这也是导致冲突的根源

 

 

 

但是只要key的 hashCode相同,计算出来的hash值就一样。如果存储的对象对多 了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。学过数据结构的同学都知道,解决hash冲突的方法有很 多,HashMap底层是通过链表(链地址法)来解决hash冲突的。

 

 开放地址法:

   当冲突发生时,通过查找数组的一个空位,并将数据填入。

  1. 线性探测

处理方式:如果index索引与当前的index有冲突,即把当前的索引index+1。如果在index+1已经存在占位现象(index+1的内容不为NULL)试图接着index+2执行。。。直到找到索引为内容为NULL的为止。这种处理方式也叫:线性地址探测法(offset-of-1)

2平方探测:以平方大小来递增下一次待探测的位置

链地址法

链地址法的基本思想是:将所有哈希地址为i 的元素构成一个称为同义词链的链表,并将链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。

在HashMap的实现中,采用的链地址法来解决冲突,它有一个桶的概念:对于Entry数组而言,数组的每个元素处存储的是链表,而不是直接的Value。在链表中的每个元素才是真正的<Key, Value>。而一个链表,就是一个桶!因此HashMap最多可以有Entry.length 个桶。

简单总结:就是在冲突的位置上建立一个链表,然后将冲突的元素插入到链表尾端

负载因子:尺寸/容量.空表的负载因子是0,而半满的负载因子是0.5.负载轻的表,出产生冲突的可能性小,对于插入和查找都是最理想的.
HashMap和HashSet都允许指定负载因子,当达到负载因子的水平时,容器将自动增加其容量(桶位数),实现方式是容量大致加倍,并重新将现有的对象分部到新的捅位中,称之为再散列.
HashMap使用的负载因子是0.75(只有当表达到四分之三时,才进行散列),这个因子在时间和空间代价中达到了平衡,更高的负载因子可以降低表所需的空间,但是会增加查找的代价.

 

 

其他方法:

1 、再散列法:建立多个hash函数,若是当发生hash冲突的时候,使用下一个hash函数,直到找到可以存放元素的位置。

2、建立公共溢出区:将哈希表分为基本表和溢出表,将与基本表发生冲突的元素放入溢出表中。

 

6. Fail-Fast机制:

我们知道java.util.HashMap不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。

这一策略在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。

 

Hashtable源码 345行

Hashtable出来的比HashMap早,HashMap 1.2才有,而Hashtable在1.0就已经出现了。HashMap和Hashtable实现原理基本一样,都是通过哈希表实现。而且两者处理冲突的方式也一样,都是通过链表法

若干方法都加了synchronized关键字,也就意味着这个Hashtable是个线程安全的类,这也是它和HashMap最大的不同点.

Hashtable每次扩容,容量都为原来的2倍加2,而HashMap为原来的2倍。

2.Hasbtable并不允许值和键为空(null),若为空,会抛空指针(HashMap可以)

3.Hashtable的容量为任意正数(最小为1),而HashMap的容量始终为2的n次方。Hashtable默认容量为        11,HashMap默认容量为      16;

  1. 4. 

 

TreeMap源码 2442行

 

   TreeMap基于红黑树实现

hashMap 详细介绍

标签:tree   fse   线性地址   hash冲突   容器   位置   offset   有一个   修改   

原文地址:https://www.cnblogs.com/KFKang/p/12037614.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!