Java源码阅读之HashMap上

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();
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值