1.HashMap:
在HashMap中,会根据hash算法来计算key-value的存储位置并进行快速存取。HashMap最多只允许一条Entry的键为NULL,但会允许多条Entry的值为NULL。HashMap是Map的一个非同步实现。
虽然 HashMap 和 HashSet 实现的接口规范不同,但是它们底层的 Hash 存储机制完全相同。实际上,HashSet 本身就是在 HashMap 的基础上实现的。
2.构造函数:
(1)HashMap() 构造一个默认初始化容量(16) 默认负载因子(0.75)
负载因子:衡量的是一个散列表的空间使用程度
成员变量 threshold 是hashMap进行扩容的阈值,他的值等于hashmap的容量*负载因子
(2)HashMap(int initalCapacity,float loadFactor)
构造一个指定初始化容量和指定负载因子的空hashmap
注意:hashMap的容量必须是2的幂次方,当hashMap的容量达到容量极限时就会进行自动扩容。
(3)HashMap(int initialCapacity)
该构造函数意在构造一个指定初始容量和默认负载因子 (0.75)的空 HashMap.
(4)HashMap(Map<? extends K, ? extends V> m)
该构造函数意在构造一个与指定 Map 具有相同映射的 HashMap
重要概念:
容量表示哈希表中桶的数量,初始容量是创建哈希表时桶的数量;负载因子时哈希表在其容量自动增长之前可以达到多满的一种尺度,它衡量的是一个散列表的空间使用程度。
特别地,若负载因子越大,那么对空间的利用更充分,但查找效率的也就越低;若负载因子越小,那么哈希表的数据将越稀疏,对空间造成的浪费也就越严重。系统默认负载因子为 0.75,这是时间和空间成本上一种折衷,一般情况下我们是无需修改的。
3.数据结构:
hashMap的数据结构是链表数组
HashMap的底层实现还是数组,只是数组的每一项都是一条链。
Entry为hashMap的内部类,Entry是构成哈希表的基石,是哈希表所存储的元素的具体形式。
4.HashMap的快速存取:
(一)存: 当我们调用put方法存值时,HashMap首先会调用Key中的HashCode方法,然后基于此获取key哈希码,然后通过哈希码迅速找到某个桶,这个桶被称为bucketIndex,然而此时任然可能存在碰撞,这时会取出bucketIndex桶内已存储的元素,并通过hashCode() 和 equals() 来逐个比较以判断Key是否已存在。如果已存在,则使用新Value值替换旧Value值,并返回旧Value值;如果不存在,则存放新的键值对<Key, Value>到桶中。
1)对NULL的特别处理:putForNullKey()
HashMap可以保存键值为NULL的键值对,且该键值对是唯一的。若要再次向其中添加键为NULL的键值对,
将覆盖其原值。若HashMap中存在键为NULL的键值对,则一定在第一个桶中
2)hash方法和indexFor()方法的作用:保证元素均匀分布到table的每一个桶中以便充分利用空间
3)HashMap中键值对的添加:HashMap总是将新的Entry对象添加到bucketIndex中,若bucketIndex处已经有了Entry
对象,那么新添加的Entry对象指向原有的entry对象,并形成一条新的以它为链头的entry链。
HashMap 永远都是在链表的表头添加新元素。此外,若HashMap中元素的个数超过极限值 threshold,其将进行扩容操作,一般情况下,容量将扩大至原来的两倍。
4)扩容:resize()
当HashMap的元素数量在数组上等于threshold,hashMap就要进行扩容。
5)transfer()
重哈希主要是一个重新计算原HashMap中的元素在新table数组中的位置并进行复制处理
(二)读:HashMap只需通过key的hash值定位到table数组的某个特定的桶,然后查找并返回该key对应的value即可
因此,调用HashMap的get(Object key)方法后,若返回值是 NULL,则存在如下两种可能:
- 该 key 对应的值就是 null;
- HashMap 中不存在该 key。
本文为看https://blog.csdn.net/justloveyou_/article/details/62893086的笔记