目录
hashMap(int)
putIfAbsent
resize()
getOrDefault
computeIfAbsent
afterNodeAccess
computeIfPresent
过程:
hashMap初始化
public HashMap(int initialCapacity) {// 传入初始化大小和加载因子this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
校验和赋值
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);}
关键的来了,返回指定大小最接近的2次幂数值
static final 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 >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}
这边返回的是阈值threshold,达到这个值就会触发扩容,你传入的是多大就是多大的容量capacity,但是阈值会按照接近的2次幂值设定,我理解如果不传入指定的长度,默认按照16*0.75来设定阈值,如果你指定了就按照上面的进行设定
是这样,入参key和value,如果key在map中存在,返回key对应的value,不存在的话把key和value插入到map中,返回null
@Override
public V putIfAbsent(K key, V value) {return putVal(hash(key), key, value, true, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node[] tab; Node p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)// hashmap为空或者长度为0,扩容,获取长度n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)// 如果数组中该位置没有数据,直接设置头节点tab[i] = newNode(hash, key, value, null);else {Node 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)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_THRESHOLD - 1) // -1 for 1st// 转化为红黑树treeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;// 链表尾插法插数据p = e;}}// e为空的话,就说明前面就没有找到key放的对应位置if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);// 这里面能找到,就返回e的值return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);// 找不到就返回nullreturn null; }
扩容hashMap
final Node[] resize() {Node[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {// 长度为最大值,直接设定为最大值threshold = Integer.MAX_VALUE;return oldTab;}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)// 容量翻倍,阈值翻倍newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in threshold// 原map容量小于0,按阈值赋值容量newCap = oldThr;else {// 阈值为0,容量为0的情况,就按默认的来// zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node[] newTab = (Node[])new Node[newCap];table = newTab;if (oldTab != null) {// 数据复制过程old tab -> new tab}return newTab;}
能从map中拿到数据,直接返回,否则返回给定值
public V getOrDefault(Object key, V defaultValue) {Node e;return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
}
这个和putIfAbsent区别就是,他这个可以通过lambda表达式进行计算出value值
如果 key 对应的 value 不存在,则使用获取 mappingFunction 重新计算后的值,并保存为该 key 的 value,否则返回 value。
public V computeIfAbsent(K key,Function super K, ? extends V> mappingFunction) {if (mappingFunction == null)throw new NullPointerException();int hash = hash(key);Node[] tab; Node first; int n, i;int binCount = 0;TreeNode t = null;Node old = null;if (size > threshold || (tab = table) == null ||(n = tab.length) == 0)// 判断要不要扩容n = (tab = resize()).length;if ((first = tab[i = (n - 1) & hash]) != null) {// key找到对应位置后,不为空if (first instanceof TreeNode)// 是否为红黑树,我就不管了,看不懂old = (t = (TreeNode)first).getTreeNode(hash, key);else {// 不是红黑树,那就是链表了Node e = first; K k;do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k)))) {// 按照key值,去查找是否存在// 找到赋值,然后赋值为旧值,breakold = e;break;}++binCount;// 每找一次,+1} while ((e = e.next) != null);}V oldValue;if (old != null && (oldValue = old.value) != null) {// 假如找到了这个值afterNodeAccess(old);return oldValue;}}// 没找到V v = mappingFunction.apply(key);if (v == null) {// lambda表达式是空,返回空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_THRESHOLD - 1)treeifyBin(tab, hash);}++modCount;++size;afterNodeInsertion(true);return v;
}
这个节点放到最后
void afterNodeAccess(Node e) { // move node to lastLinkedHashMap.Entry last;if (accessOrder && (last = tail) != e) {LinkedHashMap.Entry p =(LinkedHashMap.Entry)e, b = p.before, a = p.after;p.after = null;if (b == null)head = a;elseb.after = a;if (a != null)a.before = b;elselast = b;if (last == null)head = p;else {p.before = last;last.after = p;}tail = p;++modCount;}
}
如果 key 对应的 value 不存在,则返回该 null,如果存在,则返回通过 remappingFunction 重新计算后的值。
public V computeIfPresent(K key,BiFunction super K, ? super V, ? extends V> remappingFunction) {if (remappingFunction == null)throw new NullPointerException();Node e; V oldValue;int hash = hash(key);if ((e = getNode(hash, key)) != null &&(oldValue = e.value) != null) {V v = remappingFunction.apply(key, oldValue);if (v != null) {// 存在则覆盖这个值e.value = v;afterNodeAccess(e);return v;}else// 我理解计算出来的值为null的话,就把这个key移除掉,验证了不存在移除掉removeNode(hash, key, null, false, true);}// 不存在则返回nullreturn null;
}
示例
import java.util.HashMap;class Main {public static void main(String[] args) {// 创建一个 HashMapHashMap prices = new HashMap<>();// 往HashMap中添加映射关系prices.put("Shoes", 200);prices.put("Bag", 300);prices.put("Pant", 150);System.out.println("HashMap: " + prices);// 重新计算鞋加上10%的增值税后的价值int shoesPrice = prices.computeIfPresent("Shoes", (key, value) -> value + value * 10/100);System.out.println("Price of Shoes after VAT: " + shoesPrice);// 输出更新后的HashMapSystem.out.println("Updated HashMap: " + prices);}
}
执行以上程序输出结果为:
HashMap: {Pant=150, Bag=300, Shoes=200}
Price of Shoes after VAT: 220
Updated HashMap: {Pant=150, Bag=300, Shoes=220}}