1.定义
基于哈希表Map接口实现类
继承了AbstractMap抽象类
实现了Map接口:拥有一组Map通用的操作
实现了Cloneable接口:可进行拷贝:HashMap实现的是浅层拷贝(即拷贝对象的改变会影响被拷贝的对象)
实现了Serializable接口:表示可实现序列化,可将HashMap对象保存至本地,之后可恢复状态
特点:允许键/值 为空对象(null)
非线程安全:可通过Collections类的静态方法synchronizedMap获得线程安全的HashMap
Map map=Collections.synchronizedMap(new HashMap());
不保证有序(如插入顺序)、也不保证不随时间变化
2.数据结构
HashMap采用的数据结构=数组+单链表 (JDK1.7)JDK1.8是数组+单链表+红黑树。 该数据结构也称拉链法
数组:
核心底层=1个数组(table[])(又称哈希数组)
数组下标=经过处理的键key的hash值
数组元素=1个键值对=Entry<K,V>=1个链表(头结点)
数组大小=HashMap的容量(capacity)
单链表:
每个链表=哈希表的桶
链表的节点值=1个键值对
链表长度=桶的大小
备注:链表主要用于解决hash冲突:若不同key值计算出来的hash值相同(即都需存储到数组的同1个位置),
由于之前该hash值得数组位置已存放好元素,将原先位置的元素移到单链表中,冲突hash值对应的键值对放入到数组元素中
该采用链表解决hash冲突的方法=链地址法
注:HashMap的键值对数量=数组的键值对+所有单链表的键值对
3.主要API(方法、函数)
V get(Object key); // 获得指定键的值
V put(K key, V value); // 添加键值对
void putAll(Map<? extends K, ? extends V> m); // 将指定Map中的键值对 复制到 此Map中
V remove(Object key); // 删除该键值对
boolean containsKey(Object key); // 判断是否存在该键的键值对;是 则返回true
boolean containsValue(Object value); // 判断是否存在该值的键值对;是 则返回true
Set<K> keySet(); // 单独抽取key序列,将所有key生成一个Set
Collection<V> values(); // 单独value序列,将所有value生成一个Collection
void clear(); // 清除哈希表中的所有键值对
int size(); // 返回哈希表中所有 键值对的数量 = 数组中的键值对 + 链表中的键值对
boolean isEmpty(); // 判断HashMap是否为空;size == 0时 表示为 空
4.源码分析(put() 、get()、 resize()操作等)见链接
5.主要应用场景
统计数据
HashMap和HashTable的异同点:
相同点:
1.继承:都是实现Map接口,可克隆,可序列化
2.迭代器:都可以使用Iterator迭代器
3.存储结构:都使用哈希表
4.重复性问题:key都不能重复,value值是都可以
不同点:
1.继承的父类不同
hashtable继承自Dictionary,而HashMap继承自AbstractMap类,但二者都实现了Map接口
2.线程安全性不同
hashtable线程是安全的,因为它每个方法中都加入了Synchronize
HashMap线程是不安全的,因为:
HashMap底层是一个Entry数组,当发生hash冲突时,HashMap采用链表的方式解决冲突,
在对应的数组位置存放链表的头结点,对链表而言,新加入的节点会从头结点加入
3.是否提供contains方法
HashMap把hashtable的contains方法去掉了,改成containsValue和containsKey方法,因为contains方法容易让人误解,
hashtable则保留contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同
4.key值和value是否允许null值
其中key和value都是对象,并且不能包含重复key,但可以包含重复的value
hashtable中,key和value都不允许出现null值,但是HashMap中key和value可以为空,但key空值只能有一个
value可以重复
5.两个遍历方式的内部实现
hashtable、HashMap都使用了Iterator,HashTable还使用了枚举方式
6.hash函数:
哈希函数不同(都和key有关)
7.初始默认值
hashtable在不指定容量的情况下的默认容量为11,而HashMap为16,hashtable不要求底层数组的容量一定为2的整数次幂,而HashMap则要求一定为2的整数次幂。
8.扩容机制
hashtable扩容时,将容量变为原来的2倍加1:2*table.length+1
而HashMap扩容时,将容量变为原来的2倍:2*table.length
9.效率不同
单线程下hashMap效率比HashTable效率高
思考?为什么有了HashTable还要出现hashMap?
一般情况下集合类用在单线程下
HashTable效率较低