HashMap
HashMap基于哈希表的 Map 接口的实现。允许使用 null 值和 null 键。不保证映射的顺序,特别是它不保证该顺序恒久不变。HashMap不是线程安全的,可以通过Collections类的静态方法synchronizedMap获得线程安全的HashMap。
HashMap的底层主要是基于数组和链表来实现的。HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。
HashMap其实就是一个Entry数组,Entry对象中包含了键和值,其中next也是一个Entry对象,它就是用来处理hash冲突的,形成一个链表。
/** Entry是单向链表。
* 它是 “HashMap链式存储法”对应的链表。
*它实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数
**/
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
// 指向下一个节点
Entry<K,V> next;
final int hash;
// 构造函数。
// 输入参数包括"哈希值(h)", "键(k)", "值(v)", "下一节点(n)"
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
//......
}
HashMap类的关键属性
1 transient Entry[] table;//存储元素的实体数组 默认初始长度为 16
2
3 transient int size;//存放元素的个数
4
5 int threshold; //临界值 当实际大小超过临界值时,会进行扩容threshold = 加载因子*容量
6
7 final float loadFactor; //加载因子 默认0.75
8
9 transient int modCount;//被修改的次数
注意:
1、HashMap中通过hash&(length-1)的方法来代替取模(Hashtable中)来实现哈希值对应数组下标的映射。
2、哈希表的容量一定要是2的整数次幂,保证散列的均匀。
3、当哈希表的size>threshold时,则调用Resize方法,此方法新建一个2*size的数组,并将旧数组中的数据复制到新数组中,所以效率很低。