HashMap介绍
- 目的 通过对HashMap源码的学习,更好的理解这一常用的Java集合。
- 前提 需要了解Java基本语法。
HashMap
3.1 概念 对于 Map ,最直观就是理解就是键值对,映射,key-value 形式。一个映射不能包含重复的键,一个键只能有一个值。平常我们使用的时候,最常用的无非就是 HashMap。
HashMap 实现了 Map 接口,允许使用 null 值 和 null 键,并且不保证映射顺序。
HashMap 有两个参数影响性能:
初始容量:表示哈希表在其容量自动增加之前可以达到多满的一种尺度
加载因子:当哈希表中的条目超过了容量和加载因子的乘积的时候,就会进行重哈希操作。
如下成员变量源码:
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
transient Node<K,V>[] table;
可以看到,默认加载因子为 0.75, 默认容量为 1 << 4,也就是 16。加载因子过高,容易产生哈希冲突,加载因子过小,容易浪费空间,0.75是一种折中。
另外,整个 HashMap 的实现原理可以简单的理解成:当我们 put 的时候,首先根据 key 算出一个数值 x,然后在 table[x] 中存放我们的值。这样有一个好处是,以后的 get 等操作的时间复杂度直接就是O(1),因为 HashMap 内部就是基于数组的一个实现。
3.2 重要方法
3.2.1
V put(K key, V value)
源代码
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
上面程序中用到了一个重要的内部接口:Map.Entry,每个 Map.Entry 其实就是一个 key-value 对。从上面程序中可以看出:当系统决定存储 HashMap 中的 key-value 对时,完全没有考虑 Entry 中的 value,仅仅只是根据 key 来计算并决定每个 Entry 的存储位置。这也说明了前面的结论:我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。