map就是一个将键映射到值的一个对象。java中Map作为顶级接口,其实现类也有许多,该篇文章重点研究一下HashMap是如何实现该接口的。
HashMap实现是基于哈希表的,并且是允许键和值都为null的,但不允许重复的键出现,一旦出现则覆盖。
废话不多说直接上源码,先来看下类中定义的属性
1.默认初始容量,
这里源码中注释到,这个初始容量必须为2的次幂
请读者记住这句话,我会在后面的源码分析中解释为什么必须是2的次幂。
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
2.最大容量,很好理解,跟int的范围相关,请联系索引
static final int MAXIMUM_CAPACITY = 1 << 30;
3.无参构造时默认的加载因子,加载因子是在扩容时用到的,下文会解释。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
4.使用树结构来存放散列冲突的元素的阈值。
static final int TREEIFY_THRESHOLD = 8;
5.不使用树结构存放散列冲突的元素的阈值。
static final int UNTREEIFY_THRESHOLD = 6;
6.见名知意,最小的数结构的容量
static final int UNTREEIFY_THRESHOLD = 6;
7.节点数组,也叫表,正正存放数据节点的地方
transient Node<K,V>[] table;
8.entrySet集合
transient Set<Map.Entry<K,V>> entrySet;
9.键值对的数量
transient int size;
10.HashMap结构改变的次数,用于迭代器
transient int modCount;
11.阈值,将要扩容时的阈值
int threshold;
12.加载因子
final float loadFactor;
类中定义的静态内部类Node,该类还是比较重要的
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
该节点就是hashMap将k,v键值对放入的地方,该节点保存了四个值。1.键的hash值2.键3.值4.节点引用地址值。