变量
//默认容量,为16,如果需要自己设置的话,最好设置为2 的 n 次方 ,即使设置的不是2的次方,也会自动寻找最近的2的次方作为默认容量。至于为什么是2的次方,是为了减少hash的冲突
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//最大的容量,如果设置的超过最大容量,则map的容量为该值
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认负载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//树化的临界值,当bucket中的个数大于该数是,链表会变成红黑树
static final int TREEIFY_THRESHOLD = 8;
//非树化的临界值,当链表的个数小于该数时,红黑树会转化为链表 , 在 resize 方法中触发
static final int UNTREEIFY_THRESHOLD = 6;
put 方法:
首先会根据key来获取到它的的hash值
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
hash方法
//是通过key的hashcode来获取的,并且是支持null
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
putVal方法
//onlyIfAbsent 参数是如果不存在,就添加,如果存在的话,不进行修改 evict参数是指是否要淘汰一些数据,用于linkedList , 方法返回旧值
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//1 先判断table是否为空,如果为空的话,新创建一个table
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//2 通过 (n - 1) & hash 该方法获取到数组下标,如果对应下标存储的数据为空,直接插入就行
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
//3 如果不为空的话,需要进行遍历整个链表
else {
Node<K,V> e; K k;
//如果它的 key 与要插入的key相等或者 equals, 代表找到
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//如果不相等且是个树节点,那么插入到树节点
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//如果不相等,并且不是树节点,此时需要进行比遍历整个列表,看值是否存在
else {
for (int binCount = 0; ; ++binCount) {
//如果遍历全部列表还找不到的话,就放入链表的尾节点
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
//如果当前链表的个数大于TREEIFY_THRESHOLD ,需要进行红黑树的转化
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
//表示找到了对应的key
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
//表示该key在map中存在
if (e != null) { // existing mapping for key
V oldValue = e.value;
// 直接修改值
if (!onlyIfAbsent || oldValue == null)
e.value = value;
//该方法是为LinkedHashMap 使用的,当node 被访问过触发的事件
afterNodeAccess(e);
//直接返回
return oldValue;
}
}
//当新添加一个node时,将修改次数+1 ,
++modCount;
//当前的size 大于阈值,进行动态扩容
if (++size > threshold)
resize();
//用作LinkedHashMap 使用
afterNodeInsertion(evict);
return null;
}
remove方法
// 调用了removeNode方法
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node<K,V>[] tab; Node<K,V> p; int n, index;
//判断列表是否为空
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
//判断链表的头结点是否和要删除的相等 a
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
//如果hash相等的话,需要循环遍历整个链表,找到该节点 b
else if ((e = p.next) != null) {
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
do {
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
//如果找到该节点
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
//如果是树节点,通过树节点的进行删除
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
//如果直接是头节点的话,令头结点指向node.next ,对应 上述的 a 情况
else if (node == p)
tab[index] = node.next;
//如果不是头结点的话,对应上述的b情况,此时p为node的前一个指针,令p的next 直接等于node.next ,相当于删除node
else
p.next = node.next;
//增加修改次数
++modCount;
--size;
//该方法也用作LinkedHashMap
afterNodeRemoval(node);
return node;
}
}
return null;
}