HashMap实现了Map接口,并继承 AbstractMap 抽象类,其中 Map 接口定义了键值映射规则。AbstractMap 抽象类提供了 Map 接口的骨干实现,以最大限度地减少实现Map接口所需的工作。
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable{ ... }
初始容量 和 负载因子,这两个参数是影响HashMap性能的重要参数。其中,容量表示哈希表中桶的数量 (table 数组的大小),初始容量是创建哈希表时桶的数量;负载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。
哈希的相关概念
Hash 就是把任意长度的输入(又叫做预映射, pre-image),通过哈希算法,变换成固定长度的输出(通常是整型),该输出就是哈希值。这种转换是一种 压缩映射 ,也就是说,散列值的空间通常远小于输入的空间。不同的输入可能会散列成相同的输出,从而不可能从散列值来唯一的确定输入值。简单的说,就是一种将任意长度的消息压缩到某一固定长度的息摘要函数。
1 /** 2 * Constructs an empty HashMap with the default initial capacity 3 * (16) and the default load factor (0.75). 4 */ 5 public HashMap() { 6 7 //负载因子:用于衡量的是一个散列表的空间的使用程度 8 this.loadFactor = DEFAULT_LOAD_FACTOR; 9 10 //HashMap进行扩容的阈值,它的值等于 HashMap 的容量乘以负载因子 11 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); 12 13 // HashMap的底层实现仍是数组,只是数组的每一项都是一条链 14 table = new Entry[DEFAULT_INITIAL_CAPACITY]; 15 16 init(); 17 } 18 19 20 21 static class Entry<K,V> implements Map.Entry<K,V> { 22 23 final K key; // 键值对的键 24 V value; // 键值对的值 25 Entry<K,V> next; // 下一个节点 26 final int hash; // hash(key.hashCode())方法的返回值 27 28 /** 29 * Creates new entry. 30 */ 31 Entry(int h, K k, V v, Entry<K,V> n) { // Entry 的构造函数 32 value = v; 33 next = n; 34 key = k; 35 hash = h; 36 } 37 38 ...... 39 40 }
其中,Entry为HashMap的内部类,实现了 Map.Entry 接口,其包含了键key、值value、下一个节点next,以及hash值四个属性。事实上,Entry 是构成哈希表的基石,是哈希表所存储的元素的具体形式。
在 HashMap 中,键值对的存储是通过 put(key,vlaue) 方法来实现的,其源码如下:
1 public V put(K key, V value) { 2 3 //当key为null时,调用putForNullKey方法,并将该键值对保存到table的第一个位置 4 if (key == null) 5 return putForNullKey(value); 6 7 //根据key的hashCode计算hash值 8 int hash = hash(key.hashCode()); // ------- (1) 9 10 //计算该键值对在数组中的存储位置(哪个桶) 11 int i = indexFor(hash, table.length); // ------- (2) 12 13 //在table的第i个桶上进行迭代,寻找 key 保存的位置 14 for (Entry<K,V> e = table[i]; e != null; e = e.next) { // ------- (3) 15 Object k; 16 //判断该条链上是否存在hash值相同且key值相等的映射,若存在,则直接覆盖 value,并返回旧value 17 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 18 V oldValue = e.value; 19 e.value = value; 20 e.recordAccess(this); 21 return oldValue; // 返回旧值 22 } 23 } 24 25 modCount++; //修改次数增加1,快速失败机制 26 27 //原HashMap中无该映射,将该添加至该链的链头 28 addEntry(hash, key, value, i); 29 return null; 30 }