hashMap 详细介绍
Posted kfkang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hashMap 详细介绍相关的知识,希望对你有一定的参考价值。
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冲突的。
开放地址法:
当冲突发生时,通过查找数组的一个空位,并将数据填入。
- 线性探测
处理方式:如果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;
- 4.
TreeMap源码 2442行
TreeMap基于红黑树实现
以上是关于hashMap 详细介绍的主要内容,如果未能解决你的问题,请参考以下文章
Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
Java 集合系列07--- HashMap详细介绍(源码解析)----新