目录
hashMap(int)
过程:
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来设定阈值,如果你指定了就按照上面的进行设定
putIfAbsent
是这样,入参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<K,V>[] tab; Node<K,V> 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<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_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 key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
// 这里面能找到,就返回e的值
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
// 找不到就返回null
return null;
}
resize()
扩容hashMap
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) {
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 defaults
newCap = 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<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
// 数据复制过程
old tab -> new tab
}
return newTab;
}
getOrDefault
能从map中拿到数据,直接返回,否则返回给定值
public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
}
computeIfAbsent
这个和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<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)
// 判断要不要扩容
n = (tab = resize()).length;
if ((first = tab[i = (n - 1) & hash]) != null) {
// key找到对应位置后,不为空
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)))) {
// 按照key值,去查找是否存在
// 找到赋值,然后赋值为旧值,break
old = 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;
}
afterNodeAccess
这个节点放到最后
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
computeIfPresent
如果 key 对应的 value 不存在,则返回该 null,如果存在,则返回通过 remappingFunction 重新计算后的值。
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (remappingFunction == null)
throw new NullPointerException();
Node<K,V> 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);
}
// 不存在则返回null
return null;
}
示例
import java.util.HashMap;
class Main {
public static void main(String[] args) {
// 创建一个 HashMap
HashMap<String, Integer> 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);
// 输出更新后的HashMap
System.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}}