Java源码阅读之HashMap
类定义
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>,Cloneable,java.io.Serializable{}
类属性
// 默认的初始化容量,必须为2的幂次,后续会说明为什么必须为2的幂次
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
// 最大容量,2^30
static final int MAXMIUM_CAPACITY = 1 << 30;
// 默认的装载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f
// 当某个箱子的链表中的元素个数超过8个时,由链表改变为红黑树
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIEY_CAPACITY = 64;
// 存储键值对的表,在第一次使用的时候进行初始化,容量总是为2的幂次
transient Node<K,V>[] table;
// entrySet的缓存
transient Set<Entry<K,V>> entrySet;
// map中包含的键值对的数量
transient int size;
// 记录该map被修改的次数,修改指的是结构改变
transient int modCount;
// 当键值对的数量达到该值时进行扩容
// 如果table没有得到初始化,则该值等于指定的初始容量
// 或则等于0,表示使用的是默认的初始容量16
int threshold;
// 装载因子
final float loadFoctor;
节点内部类
static class Node<K,V> implements 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 this.key;
}
public final V getValue(){ return this.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<?,?> m = (Map.Entry<?,?>)o;
if(Objects.equals(key, o.getKey()) && Objects.equals(value, o.getValue())){
return true;
}
}
return false;
}
}
静态方法
// 这里计算hash的方式是,先计算出参数key的hash值,然后再将高16位与低16位进行异或
// 因为在hashMap中计算键值对的位置是通过取余的方法,则一般情况下高位的信息是不能得到利用的
// 这样就会增加冲突的概率,所以采用这种方式来将高位的信息向下传递
static int hash(Object key){
int h;
return (key == null) ? 0 : h = key.hashCode() ^ h >>> 16;
}
// 如果x是Compable的对象,则放回x的class信息,否则返回null
static Class<?> classForComparable(Object x){
if(x instanceof Comparable){
Class<?> c;
Type[] ts, as;
Type t;
ParameterizedType p;
if((c = x.getClass()) == String.class){
return c;
}
if((ts = c.getGenericInterfaces()) != null){
for(int i = 0; i < ts.length; i ++){
if(((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType)t).getRawType() == Comparable.class) && (as = p.getActuallyTypeArguments()) != null && as.length == 1 && as[0] == c){
return c;
}
}
}
}
return null;
}
static int compareComparables(Class<?> kc, Object k, Object x){
return (x == null || x.getClass() != kc) ? 0 : (Comparable)k.compareTo(x);
}
static int tableSizeFor(int cap){
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXMIUM_CAPACITY) ? MAXMIUM_CAPACITY : n + 1;
}
构造方法
// 用指定的容量和装载因子创建map
public HashMap(int initialCapacity, float loadFoctor){
// 如果指定的初始容量小于0则抛出异常
if(initialCapacity < 0){
throw new IllegaArgumentException("Illegal initial Capacity: " + initialCapacity);
}
if(initialCapacity > MAXMIUM_CAPACITY)
//如果指定的容量大于最大容量,则初始化为最大容量
initialCapacity = MAXMIUM_CAPACITY;
if(loadFoctor < 0 || Float.isNaN(loadFoctor)){
throw new IllegalArgumentException("Illegal load foctor: " + loadFoctor);
}
this.loadFoctor = loadFoctor;
// map的容量必须为2的幂次
this.threshold = talbeSizeFor(initialCapacity);
}
// 用指定的容量和默认的装载因子创建Map
public HashMap(int initialCapacity){
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
// 创建一个默认的hashMap
public HashMap(){
this.loadFoctor = DEFAULT_LOAD_FACTOR;
}
// 使用已有的Map创建新map
// 使用默认的装载因子和能保证m中键值对数量的最小容量初始化Map
public HashMap(Map<? extends K, ? extends V> m){
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
方法
// m: 需要添加的map
// evict: 在初始化Map的时候为false,否则为true
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict){
int s = m.size();
if(table == null){
// map还没有得到初始化,第一次使用
// 加1是规避小数,向上取整
float ft = ((float)s / loadFoctor) + 1.0F;
int t = (ft < (float) MAXMIUM_CAPACITY) ? (int)ft : MAXMIUM_CAPACITY;
if(t > threshold){
// 初始化容量
threshold = tableSizeFor(t);
}
}else if(s > threshold){
// 对Map进行扩容
resize();
}
for(Map.Entry<? extends K, ? extends V> e : m.entrySet()){
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
// 获取指定键关联的值,如果没有则返回null
public V get(Object key){
Node<K,V> e;
return (e = getNode(hash(key), key) == null) ? null : e.getValue();
}
// 根据键获取指定的值
public Node<K,V> getNode(int hash, Object key){
Node<K,V>[] tab; Node<K,V> first,e; int n; K k;
if((tab = table) != null && (n =tab.length) > 0 &&
(first = tab[(n-1) & hash]) != null){
// table不为空,且目标位置有元素存在
// 先检查第一个元素是否就是目标
if((first.hash == hash) && ((first.key == key) ||(key != null && key.equals(first.key)))){
return first;
}
// 如果当前第一个元素不是目标元素,则在后续中查找是否有目标元素
if((e = first.next) != null){
if(first instanceof TreeNode){
// 当前桶中的元素是以红黑树的形式进行组织的
return ((TreeNode<K,V>)first).getTreeNode(hash,key);
}
do{
// 当前桶中的元素是以链表的形式进行组织
if(e.hash == hash && (e.key == key || (key != null && key.equals(e.key))))
return e;
}while((e = e.next) != null);
}
}
return null;
}
// 向map中添加一个键值对,如果已经存在指定的键则对值进行替换
// 如果已经存在指定的键,则返回旧值否则返回null
public V put(K key, V value){
return putVal(hash(key), key, value, false, true);
}
// 向map中添加键值对
// onlyIfAbsent: 如果为true,则不该变原来的值
// evict如果为false,则在创建map阶段
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict){
Node<K,V> tab; Node<K,V> p; int n, i;
if((tab = table) == null || (n = table.length) == 0){
// 说明map还没有被初始化,进行初始化
n = (tab = resize()).length;
}
if((p = tab[i =(n - 1) & hash]) == null){
// 该位置没有键值对,说明之前不存在该键
tab[i] = newNode(hash, key, value, null);
}else{
// 该位置已经存在值了,需要判断该键是否已经存在
Node<K,V> e; K k;
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);
if(binCount >= TREEIFY_THERSHOLD - 1){
// 当前链表中的元素达到8个,需要转变成红黑树结构
treeifyBin(tab, hash);
break; // 退出循环
}
}
if(e.hash == hash && (e.key == key || (key != null && key.equals(e.key)))){
// 当前键已经存在,更新值即可
break;
}
p = e;
}
}
if(e != null){
// 说明键值对在map中已经存在
V oldValue = e.value;
if(!onlyIfAbsent || oldValue == null){
// 只有在需要修改或则不许修改但旧值为空的时候进行修改
e.value = value;
}
afterNodeAccess(e);
return oldValue;
}
}
// 指定的键原先不存在与map中
modCount ++;
if(++size > threshold){
// 超过阈值,进行扩容
resize();
}
afterNodeInsertion(evict);
return null;
}
// 对map进行初始化或则扩充map的容量为2倍
final Node<K,V>[] resize(){
Node<K,V>[] oldTab = table;
// 获取原始的容量
int oldCap = (oldTab == null) ? 0 : oldTab.length;
// 获取原有的扩容上界
int oldThr = threshold;
int newCap, newThr = 0;
if(oldCap > 0){
// 说明table已经被初始化过了,现在需要进行扩容
if(oldCap >= MAXMIUM_CAPACITY){
// 不能再进行扩容了
threshold = Integer.MAX_VALUE;
return oldTab;
}else if((newCap = oldCap << 1) < MAXMIUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY){
// 注意这里最大只能扩容到2^29,扩容到2^30次的时候不会更新newThr,newThr=0
// 且如果初始化容量小于16,不会更新newThr
// 阈值同样扩大两倍
newThr = oldThr << 1;
}
}else if(oldThr > 0){
// oldCap = 0,说明table还没有被初始化,且threshold大于0,说明是用自定义的初始容量初始化map
// 用oldThr替代newCap
newCap = oldThr;
}else{
// oldThr == 0,说明采用的是默认的容量和默认的装载因子
newCap = DEFALUT_INITIAL_CAPACITY;
newThr = (int)(DEFALUT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
}
if(newThr == 0){
// newThr == 0这有三种情况
// 1.当前容量为2^29,现扩容至2^30,因为到2^30次时,thr会更新到Integer.MAX_VALUE;
// 2.当前容量<16,
// 3.在第一次进行初始化时,且容量是自定义容量
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXMIUM_CAPACITY && (int)ft < MAXMIUM_CAPACITY) ? (int)ft : Integer.MAX_VALUE;
}
threshold = newThr;
Node<K,V>[] newTab = (Node<K,V>) new Node[newCap];
table = newTab;
if(oldTab != null){
// 说明该操作是进行扩容,要将原table中的元素移动至新的table中
for(int j = 0; j < oldCap; j++){
Node<K,V> e;
if((e = oldTab[j]) != null){
// 当前桶中装有元素
oldTab[j] = null;// 防止对象游离
if(e.next == null){
// 当前桶中只有一个元素
// 将该元素装入新tab中
newTab[e.hash & (newCap - 1)] = e;
}else if(e instanceof TreeNode){
// 说明当前桶中的元素超过8个,改用红黑树结构
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
}else{
// 说明当前桶中的元素不足8个,是链表结构
Node<K,V> loHead = null, loTail = null; // 扩容后仍在原处的链表
Node<K,V> hiHead = null, hiTail = null; // 扩容后会移动到新位置上的链表
Node<K,V> next;
do{
next = e.next;
if((e.hash & oldCap) == 0){
// 该元素仍在该位置
if(loTail == null){
loHead = e;
}else{
loTail.next = e;
}
loTail = e;
}else{
// 该元素会移动到新位置上
if(hiTail == null){
hiHead = e;
}else{
hiTail.next = e;
}
hiTail = e;
}
}while((e = next) != null);
if(loTail != null){
// 说明链表中有元素
loTail.next = null;
newTab[j] = loHead;
}
if(hiTail != null){
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTable;
}
// 从map中移除指定的键对应的键值对
// 如果存在指定的键值对,则返回相应的值并移除键值对
// 如果不存在键值对,则返回null
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;
if((p.hash == hash) && ((k = p.key) == key || (key != null && key.equals(k)))){
// 当前第一个元素就是目标元素
node = p;
}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的前一个
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.removeNode(this, tab, movable);
}else if(node == p){
tab[index] = node.next;
}else{
p.next = node.next;
}
++modeCount;
--size;
afterNodeRemoval(node);
return node;
}
}
return null;
}
// 移除map中的所有键值对
public void clear(){
Node<K,V> tab; int n;
modCount ++;
// 首先判断map中是否有元素
if((tab = table) != null && size > 0){
size = 0;
for(int i = 0; i < n; i++){
tab[i] = null;
}
}
}
// 检测map中是否含有指定的值
public boolean containsValue(Object value){
Node<K,V>[] tab; V v;
if((tab = table) != null && size > 0){
// Map中有元素存在
for(int i=0; i < tab.length; i++){
for(Node<K,V> p = tab[i]; p != null; p = p.next){
if((v = p.value) == value || (value != null && (value.equals(v)))){
return true;
}
}
}
}
return false;
}
视图
视图主要是指在map中关于键、值和键值对的视图
final class KeySet extends AbstractSet<K>{
public final int size() { return size; }
// 对视图的改变会引起原集合的改变
public final void clear() {HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
// 调用Map的ContainsKey方法进行判断
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key){
// 移除指定key所关联的键值对
return removeNode(hash(key), key, null, false, true) != null;
}
// 返回一个可以分割的在键的集合上的迭代器
public final Spliterator<K> spliterator(){
return new KeySpliterator(HashMap.this, 0, -1, 0, 0);
}
// 遍历键集合中的所有元素
public final void forEach(Consumer<? super K> action){
Node<K,V> tab;
if(action == null){
throw new NullPointerException();
}
if(size > 0 && (tab = table) != null){
int mc = modCount;
for(int i = 0; i < tab.length; ++i){
for(Node<K,V> p = tab[i]; p != null; p=p.next){
action.accpet(p.key);
}
}
if(mc != modCount){
throw new ConcurrentModificationException();
}
}
}
}
// 创建一个map的键集合的视图
public Set<K> keySet(){
Set<K> ks;
if((ks = keySet) == null){
ks = new KeySet();
keySet = ks;
}
return ks;
}
// 值集合的视图
final class Values extends AbstractCollection<V>{
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
// 值集合的迭代器
public final Iterator<V> iterator() { return new ValueIterator(); }
public final boolean contains(Object o) { return containsValue(o); }
// 创建值集合的可分割的迭代器
public final Spliterator<V> spliterator(){
return new KeySpliterator(this, 0, -1, 0, 0);
}
// 遍历值集合中的所有元素
public final void forEach(Consumer<? super V> action){
Node<K,V> tab;
if(action == null){
throw new NullPointerException();
}
if(size > 0 && (tab = table) != null){
int mc = modCount;
for(int i = 0; i < tab.length; i++){
for(Node<K,V> p = tab[i]; p != null; p = p.next){
action.accpet(p.value);
}
}
if(mc != modCount){
throw new ConcurrentComodificationException();
}
}
}
}
// 返回值集合的视图
public Collection<V> values(){
Collection<V> vals;
if((vals = values) == null){
vals = new Values();
values = vals;
}
return vals;
}
// 键值对集合,支持remove等一系列方法,不支持添加方法
final class EntrySet extends AbstractSet<Map.Entry<K,V>>{
public final int size(){
return size;
}
public final void clear(){
HashMap.this.clear();
}
public final Iterator<Map.Entry<K,V>> iterator(){
return new EntryIterator();
}
public final boolean contains(Object o){
if(!(o instanceof Map.Entry<?,?>)){
return false;
}
Map.Entry<?,?> m = (Map.Entry<?,?>)o;
Object key = m.getKey();
Node<K,V> candiate = getNode(hash(key), key);
return (candiate != null) && candiate.equals(e);
}
public final boolean remove(Object o){
if(o instanceof Map.Entry<?,?>){
Map.Entry<?,?> m = (Map.Entry<?,?>)o;
Object key = m.getKey();
Object value = m.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator<Map.Entry<?,?>> spliterator(){
return new EntrySpliterator(this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action){
Node<?,?>[] tab;
if(action == null){
throw new NulPointerException();
}
if(size > 0 && (tab = table) != null){
int mc = modCount;
for(int i = 0; i < tab.length; i++){
for(Node<?,?> p = tab[i]; p != null; p = p.next){
action.accpet(p);
}
}
if(mc != modCount){
throw new ConcurrentMododificationException();
}
}
}
}
Java8新增的方法
// 通过键获取指定的值,如果没有指定的值则返回默认值
public V getOrDefault(Object key, V defaultValue){
Node<K,V> e;
return (e = getNode(hash(key)) == null) ? defaultValue : e.value;
}
// 只有当指定的键不存在时,才进行添加。或则指定的键关联的是null值进行添加
public V putIfAbsent(K key, V value){
return putVal(hash(key), key, value, true, true);
}
public boolean replace(K key, V oldValue, V newValue){
Node<K,V> e; V v;
if((e = getNode(hash(key),key)) != null && ((v = e.value) == value || (newValue != null && newValue.equals(v)))){
e.value = newValue;
afterNodeAccess(e);
return true;
}
return false;
}
public V replace(K key, V value){
Node<K,V> e;
if((e = getNode(hash(key), key)) != null){
V oldValue = e.value;
e.value = value;
afterNodeAccess(e);
return oldValue;
}
return null;
}
// 如果指定的键不存在,则通过mappingFunction计算出key所关联的值并插入map中
// 或则键存在但是键所关联的值是null值,且计算出来的新值替代原有的null值
// 如果计算出来的是null值则什么不做
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction){
if(mappingFunction == null){
throw new NullPointerException();
}
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
if(size > threshold || (tab = table) == null || (n = tab.length) == 0){
// 如果容量达到阈值,则进行扩容
// 如果table还没有进行初始化,则对table进行初始化
n = (tab = reszie()).length;
}
if((first = tab[(i = (n - 1) & hash])) != null){
// 说明目标桶中已经有元素存在
if(first instanceof TreeNode){
old = (t = ((TreeNode<K,V>)first)).getTreeNode(hash, key);
}else{
Node<K,V> e = first; K k;
do{
if(e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))){
old = e;
break;
}
++binCount;
}while((e = e.next) != null);
}
V oldValue = null;
if(old != null && (oldValue = old.value) != null){
// 说明键已经存在,且关联的有值,则不进行任何操作,返回旧值即可
afterAccessNode(old);
return oldValue;
}
}
// 说明键不存在,或则键存在但是关联的是null值
// 计算新的值
V v = mappingFunction.apply(key);
if(v == null){
// 如果计算出来的新值也为null,则不作任何操作
return null;
}else if(old != null){
// 键已经存在
old.value = v;
afterNodeAccess(old);
return v;
}else if(t != null){
// 键不存在,且当前桶中的数据结构为红黑树
t.putTreeVal(this, tab, hash, key, v);
}else{
// 键不存在,且当前桶中的数据结构为链表
// 将键值对插入桶中的第一个元素
tab[i] = newNode(hash, key, v, first);
if(binCount >= TREEIFY_THERSHOLD - 1){
// 将数据结构由链表转换为红黑树
treeifyBin(tab, hash);
}
}
++modCount;
++size;
afterNodeInstion(true);
return v;
}
// 如果指定的键值对集合中已经存在(指的是值不为null),则通过制定的remappingFunction对值进行替换
// 如果指点的键在集合中已经存在,且关联的是null值则不进行任何操作,直接返回null
// 如果remappingFunction计算出来的新值为null,则对节点进行删除
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction){
if(remappingFunction == null){
throw new NullPointerException();
}
// 计算出当前key的hash值
int hash = hash(key);
// 已经存在的节点和值
Node<K,V> old; V oldValue;
if((old = getNode(hash, key)) != null && (oldValue = old.value) != null){
// 键值对在map中已经存在
V v = remappingFunction(key, oldValue);
if(v != null){
// 如果新计算出来的值不为空,则进行值的替换
old.value = v;
afterNodeAccess(old);
return oldValue;
}else{
// 计算出来的值为null值,则删除指定的键值对
removeNode(hash, key, null, false, true);
}
}
return null;
}
// 不管map中是否存在指定的键,都进行操作
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction){
if(remappingFunction == null){
throw new NullPointerException();
}
// 计算出当前key值的hash值
int hash = hash(key);
// tab是指当前map集合的table,first是指目标桶中的第一个元素,n是指map当前的容量,i是目标桶在map中的索引
Node<K,V>[] tab; Node<K,V> first; int n, i;
// 用于缓存当前红黑树的根节点
TreeNode<K,V> t = null;
Node<K,V> old = null;
int binCount = 0;
// 因为该方法可能会在map中添加元素,所以需要确保容量充足
if(size > threshold || (tab = table) == null || (n = tab.length) == 0){
// 对map进行扩容或进行初始化
n = (tab = resize()).length;
}
if((first = tab[(i = (n - 1) & hash)]) != null){
// 目标桶中有元素
if(first instanceof TreeNode){
// 当前桶中的元素是以红黑树的结构进行组织的
old = (t = ((TreeNode<K.V>)first)).getTreeNode(hash, key);
}else{
// 当前桶中的元素是以链表的形式进行组织的
Node<K,V> e = first; K k;
do{
if(e.hash == hash && ((k = e.key) == key) || (key != null && key.equals(k))){
old = e;
}
// 用于记录当前桶中已经有的元素的数目,用于后续添加元素的时候判断是否需要转变数据结构
++binCount;
}while((e = e.next) != null);
}
}
V oldValue = (old == null) ? null : old.value;
V v = remappingFunction.apply(key, oldValue);
if(old != null){
// 原有的键存在
if(v != null){
old.value = v;
afterAccessNode(old);
}else{
// 如果计算出来的值为null,则移除原有的节点
removeNode(hash, key, null, false, true);
}
}else if(v != null){
// 没有关联的键值对,且计算出来的新值不为空
if(t != null){
t.putTreeNode(this, tab, hash, key, value);
}else{
tab[i] = newNode(hash, key, v, first);
if(binCOunt >= TREEIFY_THERSHOLD - 1){
treeifyBin(tab, hash);
}
}
++modCount;
++szie;
afterNodeInsertion(true);
}
return v;
}
// 根据指定的值结合原有的值生成新的值来替换原有的值
// 如果在map中键key不存在,且value不为null,则将新的键值对插入map
// 如果键key在map中已经存在,且value不为null,则原来的value和新的value进行计算,生成新的值,如果新的值为null则进行删除
// 如果原有值为null则用新的值进行替换
// 返回值有三种情况,1。value,2.一个新值,3.null
public V merge(K key, V value, BiFunction<? super K, ? super V, ? extends V> remappingFunction){
if(value == null){
throw new NullPointerException();
}
if(remappingFunction == null){
throw new NullPointerException();
}
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
if(size > thershold || (tab = table) == null || (n = tab.length) == 0){
n = (tab = resize()).length;
}
if((first = tab[(i = (n - 1)&hash)]) != null){
if(first instanceof TreeNode){
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
}else{
Node<K,V> e = first; K k;
do {
if(e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))){
old = e;
break;
}
binCount++:
}while((e = e.next) != null);
}
}
if(old != null){
V v;
if(old.value == null){
v = value;
}else{
v = remappingFunction.apply(old.value, value);
}
if(v != null){
old.value = v;
afterNodeAccess(old);
}else{
removeNode(hash, key, oldValue, true, true);
}
return v;
}
if(value != null){
if(t != null){
t.putTreeNode(this, tab, hash, key, value);
}else{
tab[i] = newNode(hash, key, value, first);
if(binCOunt >= TREEIFY_THERSHOLD - 1){
treeifyBin(tab, hash);
}
}
++modCount;
++size;
afterNodeInsertion(true);
}
return value;
}
public void forEach(BiConsumer<? super K, ? super V> action){
if(action == null){
throw new NullPointerException();
}
Node<K,V>[] tab;
if(size > 0 && (tab = table)!=null){
int mc = modCount;
for(int i = 0; i < tab.length; i++){
for(Node<K,V> e = tab[i]; e != null; e = e.next){
action.accept(e.key, e.value);
}
}
if(mc != modCount){
throw new ConcurrentComodificationException();
}
}
}
public void replaceAll(BiFunction<? super K , ? super V, ? extends V> action){
if(action == null){
throw new NullPointerException();
}
Node<K,V>[] tab;
if(size > 0 && (tab = table) != null){
int mc = modCount;
for(int i = 0; i <tab.length; i++){
for(Node<K,V> e = tab[i]; e != null; e = e.next){
e.value = action.apply(e.key, e.value);
}
}
if(mc != modCount){
throw new ConcurrentComodificationException();
}
}
}