源码
1. 实现Cloneable接口,重写clone方法,以支持浅拷贝;实现Serializable接口,以支持序列化,静态成员变量serialVersionUID为序列化ID,以保证序列化与反序列化双方的类版本一致性
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
@java.io.Serial
private static final long serialVersionUID = 362498820763181265L;
2. 静态成员变量
// table的初始容量为16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
// table的最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认的负载因子为0.75,即容量为n的table最多放n*0.75个
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//当table容量超过64时,链表长度超过8的会被转化为红黑树
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
- 关于负载因子:个人认为,hash表产生冲突的概率随表内元素增加而增加,之所以不等表满了再扩,是为了保持性能。
- 链表->红黑树,阈值为什么是8:链表的查找复杂度为O(n/2),红黑树查找复杂度为O(logn),当n=8时,n/2 < log n
- 比较好奇的点是为什么有的定义用的位运算,有的用的整数?
//静态节点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;
return o instanceof Map.Entry<?, ?> e
&& Objects.equals(key, e.getKey())
&& Objects.equals(value, e.getValue());
}
}