- 1、本文档共22页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
Java集合深入理解HashMap主要特点和关键方法源码解读
Java 集合深入理解(16):HashMap 主要特点和关键方法源码解读
什么是 HashMap
HashMap 是一个采用哈希表实现的键值对集合,继承自?AbstractMap,实现了?Map 接口?。?HashMap 的特殊存储结构使得在获取指定元素前需要经过哈希运算,得到目标元素在哈希表中的位置,然后再进行少量比较即可得到元素,这使得 HashMap 的查找效率贼高。
当发生 哈希冲突(碰撞)的时候,HashMap 采用?拉链法?进行解决(不熟悉 “哈希冲突” 和 “拉链法” 这 2 个概念的同学可以点这里了解),因此 HashMap 的底层实现是?数组+链表,如下图 所示:
HashMap 的特点
结合平时使用,可以了解到 HashMap 大概具有以下特点:
底层实现是 链表数组,JDK 8 后又加了 红黑树
实现了 Map 全部的方法
key 用 Set 存放,所以想做到?key 不允许重复,key 对应的类需要重写 hashCode 和 equals 方法
允许空键和空值(但空键只有一个,且放在第一位,下面会介绍)
元素是无序的,而且顺序会不定时改变
插入、获取的时间复杂度基本是 O(1)(前提是有适当的哈希函数,让元素分布在均匀的位置)
遍历整个 Map 需要的时间与 桶(数组) 的长度成正比(因此初始化时 HashMap 的容量不宜太大)
两个关键因子:初始容量、加载因子
除了不允许 null 并且同步,Hashtable 几乎和他一样。
下面结合源码进行验证这些特点。
HashMap 的 13 个成员变量
1.默认初始容量:16,必须是 2 的整数次方
static final int DEFAULT_INITIAL_CAPACITY = 1 4;
2.默认加载因子的大小:0.75,可不是随便的,结合时间和空间效率考虑得到的
static final float DEFAULT_LOAD_FACTOR = 0.75f;
3.最大容量: 2^ 30 次方
static final int MAXIMUM_CAPACITY = 1 30;
4.当前 HashMap 修改的次数,这个变量用来保证?fail-fast?机制
transient int modCount;
5.阈值,下次需要扩容时的值,等于 容量*加载因子
int threshold;
6.树形阈值:JDK 1.8 新增的,当使用 树 而不是列表来作为桶时使用。必须必 2 大
static final int TREEIFY_THRESHOLD = 8;
7.非树形阈值:也是 1.8 新增的,扩容时分裂一个树形桶的阈值(?不是很懂 - -),要比 TREEIFY_THRESHOLD 小
static final int UNTREEIFY_THRESHOLD = 6;
8.树形最小容量:桶可能是树的哈希表的最小容量。至少是 TREEIFY_THRESHOLD 的 4 倍,这样能避免扩容时的冲突
static final int MIN_TREEIFY_CAPACITY = 64;
9.缓存的 键值对集合(另外两个视图:keySet 和 values 是在?AbstractMap?中声明的)
transient SetMap.EntryK,V entrySet;
10.哈希表中的链表数组
transient NodeK,V[] table;
11.键值对的数量
transient int size;
12.哈希表的加载因子
final float loadFactor;
HashMap 的初始容量和加载因子
由于 HashMap 扩容开销很大(需要创建新数组、重新哈希、分配等等),因此与扩容相关的两个因素:
容量:数组的数量
加载因子:决定了 HashMap 中的元素占有多少比例时扩容
成为了 HashMap 最重要的部分之一,它们决定了 HashMap 什么时候扩容。
HashMap 的默认加载因子为 0.75,这是在时间、空间两方面均衡考虑下的结果:
加载因子太大的话桶太多,遍历时效率变低
太小的话频繁 rehash,导致性能降低
当设置初始容量时,需要提前考虑 Map 中可能有多少对键值对,设计合理的加载因子,尽可能避免进行扩容。
如果存储的键值对很多,干脆设置个大点的容量,这样可以少扩容几次。
HashMap 的关键方法
1. HashMap 的 4 个构造方法
//创建一个空的哈希表,初始容量为 16,加载因子为 0.75
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
//创建一个空的哈希表,指
文档评论(0)