HashMap是一个散列表,这个散列表包含的散列桶的格式为2^n个,而且必须满足这个条件,原因在getNode(int hash, Object key)
这个方法的分析中给出。HashMap允许null的键值对,null的键值对总会被映射到第一个散列桶中。HashMap里面的键值对并没有顺序之分,里面的结构是使用数组+链表或者是红黑树,是否将链表变成红黑树的条件是,一个桶里面节点的个数大于MIN_TREEIFY_CAPACITY
static final int MIN_TREEIFY_CAPACITY = 64;
HashMap的容量是指散列桶的个数,在构造函数中传入,如果构造时传入的参数不满足这个条件,内部会做相应的调整,以满足,HashMap的构造函数如下:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
默认的HashMap大小为16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
HashMap是一个散列表,散列表的节点是Node这个类
//Node实现了Map类里面的Entry接口
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; }
/* 节点的哈希码,注意这个并不是用来定位key的位置的哈希码方法,
* 获得key的哈希码的方法是HashMap.hash方法,使用这个哈希码来决
* 定该key存放在哪个散列桶内
*/
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) {
//相等的依据是两者引用相等,或者两者的key、value分别相等
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;
}
}
每个节点的哈希码是以key的哈希码来计算的,具体计