HashMap的原理

散列法(hashing)或哈希法是一种将字符组成的字符串转换为固定长度(一般是更短长度)的数值或索引值的方法。

HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。HashMap存储的是键值对,HashMap很快。该类不保证映射的顺序,特别是它不保证该顺序恒久不变。

HashMap实质上是一个“链表散列”的数据结构,即数组和链表的结合体。

数组:存储区间连续,占用内存严重,寻址容易,插入删除困难;

链表:存储区间离散,占用内存比较宽松,寻址困难,插入删除容易。

HashMap综合应用了这两种数据结构,实现了寻址容易,插入删除容易。

HashMap的基本存储原理以及存储内容的组成

基本原理:先声明一个下标范围比较大的数组来存储元素。另外设计一个哈希函数(也叫散列函数)来获得每一个元素的key(关键字)的函数值(即数组下标,hash值)相对应,数组存储的元素是一个Entry类,这个类有三个数据域,key、value(键值对),next(指向下一个Entry)。

“直接定址”和“解决冲突”是哈希表的两大特点。

HashMap的工作原理以及存取方法过程

工作原理:HashMap是基于散列法(又称哈希法hashing)的原理,使用put(key,value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket(桶)位置来存储Entry对象。HashMap是在bucket中存储键对象和值对象,作为 Map.Entry。并不是仅仅只在bucket中存储值。

HashMap具体的存取过程如下:

put键值对的方法的过程是:

1、获取key;

2、通过hash函数得到hash值;int hash=key.hashCode();//获取key的hashCode,这个值是一个固定的int值

3、得到桶号(一般都为hash值对桶数求模),也即数组下标int index=hash%Entry[].length;//获取数组下标:key的hash值对Entry数组长度进行取余

4、存放key和value在桶内:table[index]=Entry对象;

get值方法的过程是:

1、获取key

2、通过hash函数得到hash值:int hash=key.hashCode();

3、得到桶号(一般都为hash值对桶求模):int index=hash%Entry[].length;

4、比较桶的内部元素是否与key相等,若都不相等,则没有找到。

5、取出相等的记录的value。

HashMap中直接地址用hash函数生成;解决冲突,用比较函数解决。如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值时,许多查询就会更快了(指查不到的时候)。

不可变对象的好处

上面说到使用包装类时刻作为键的原因是String,Interger这样的wrapper类作为HashMap的键是很合适的,而且String最为常用。因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。

猜你喜欢

转载自blog.csdn.net/alice_0_0/article/details/80732372