HashMap

第1部分 HashMap介绍

  1. HashMap简介
  2. HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
  3. HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。
  4. HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射是无序的。
  5. HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

HashMap的构造函数

 

第2部分 HashMap数据结构

从图中可以看出: 

(1) HashMap继承于AbstractMap类,实现了Map接口。Map是"key-value键值对"接口,AbstractMap实现了"键值对"的通用函数接口。 

(2) HashMap是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, size, threshold, loadFactor, modCount。

table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。 

size是HashMap的大小,它是HashMap保存的键值对的数量。 

threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。threshold的值="容量*加载因子",当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。

loadFactor就是加载因子。 

modCount是用来实现fail-fast机制的。

第3部分 HashMap源码解析(基于JDK1.6.0_45)

HashMap就是一个散列表,它是通过“拉链法”解决哈希冲突的。

第3.1部分 HashMap的“拉链法”相关内容

3.1.1 HashMap数据存储数组

transient Entry[] table;

HashMap中的key-value都是存储在Entry数组中的。

3.1.2 数据节点Entry的数据结构

Entry 实际上就是一个单向链表。这也是为什么我们说HashMap是通过拉链法解决哈希冲突的。

Entry 实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数。这些都是基本的读取/修改key、value值的函数。

第3.2部分 HashMap的主要对外接口

3.2.1 clear()

clear() 的作用是清空HashMap。它是通过将所有的元素设为null来实现的。

 

3.2.2 containsKey()

containsKey() 的作用是判断HashMap是否包含key。

containsKey() 首先通过getEntry(key)获取key对应的Entry,然后判断该Entry是否为null。

getEntry() 的作用就是返回“键为key”的键值对,它的实现源码中已经进行了说明。

这里需要强调的是:HashMap将“key为null”的元素都放在table的位置0处,即table[0]中;“key不为null”的放在table的其余位置!

3.2.3 containsValue()

containsValue() 的作用是判断HashMap是否包含“值为value”的元素。

从中,我们可以看出containsNullValue()分为两步进行处理:第一,若“value为null”,则调用containsNullValue()。第二,若“value不为null”,则查找HashMap中是否有值为value的节点。

containsNullValue() 的作用判断HashMap中是否包含“值为null”的元素。

3.2.4 entrySet()、values()、keySet()

它们3个的原理类似,这里以entrySet()为例来说明。

entrySet()的作用是返回“HashMap中所有Entry的集合”,它是一个集合。

HashMap是通过拉链法实现的散列表。表现在HashMap包括许多的Entry,而每一个Entry本质上又是一个单向链表。

当我们通过entrySet()获取到的Iterator的next()方法去遍历HashMap时,实际上调用的是 nextEntry() 。而nextEntry()的实现方式,先遍历Entry(根据Entry在table中的序号,从小到大的遍历);然后对每个Entry(即每个单向链表),逐个遍历。

方 法

get() 的作用是获取key对应的value。

put() 的作用是对外提供接口,让HashMap对象可以通过put()将“key-value”添加到HashMap中。

若要添加到HashMap中的键值对对应的key已经存在HashMap中,则找到该键值对;然后新的value取代旧的value,并退出!

若要添加到HashMap中的键值对对应的key不在HashMap中,则将其添加到该哈希值对应的链表中,并调用addEntry()。

addEntry() 的作用是新增Entry。将“key-value”插入指定位置,bucketIndex是位置索引。

putAll() 的作用是将"m"的全部元素都添加到HashMap中。

remove() 的作用是删除“键为key”元素。

addEntry()和createEntry() 区别

(01) addEntry()一般用在 新增Entry可能导致“HashMap的实际容量”超过“阈值”的情况下。

       例如,我们新建一个HashMap,然后不断通过put()向HashMap中添加元素;put()是通过addEntry()新增Entry的。

       在这种情况下,我们不知道何时“HashMap的实际容量”会超过“阈值”;

       因此,需要调用addEntry()。

(02) createEntry() 一般用在 新增Entry不会导致“HashMap的实际容量”超过“阈值”的情况下。

        例如,我们调用HashMap“带有Map”的构造函数,它绘将Map的全部元素添加到HashMap中;

       但在添加之前,我们已经计算好“HashMap的容量和阈值”。也就是,可以确定“即使将Map中的全部元素添加到HashMap中,都不会超过HashMap的阈值”。

       此时,调用createEntry()即可。

第3.3部分 HashMap实现的Cloneable接口

HashMap实现了Cloneable接口,即实现了clone()方法。

clone()方法的作用很简单,就是克隆一个HashMap对象并返回。

第3.4部分 HashMap实现的Serializable接口

HashMap实现java.io.Serializable,分别实现了串行读取、写入功能。

串行写入函数是writeObject(),它的作用是将HashMap的“总的容量,实际容量,所有的Entry”都写入到输出流中。

而串行读取函数是readObject(),它的作用是将HashMap的“总的容量,实际容量,所有的Entry”依次读出。

第4部分 HashMap遍历方式

4.1 遍历HashMap的键值对

第一步:根据entrySet()获取HashMap的“键值对”的Set集合。

第二步:通过Iterator迭代器遍历“第一步”得到的集合。

4.2 遍历HashMap的键

第一步:根据keySet()获取HashMap的“键”的Set集合。

第二步:通过Iterator迭代器遍历“第一步”得到的集合。

4.3 遍历HashMap的值

第一步:根据value()获取HashMap的“值”的集合。

第二步:通过Iterator迭代器遍历“第一步”得到的集合。

第5部分 HashMap示例

 示例代码

输出结果

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值