内容简介:首先涉及三个成员变量:
1. HashMap中Node类:
static class Node<K,V> implements Map.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 key; }
public final V getValue() { return 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<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
- 重写hashCode,key和value的hashcode取异或。
- 重写equals,当为同一个对象或是同一个key和同一个value都认为这两个对象相等。
2.散列值的计算
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
- 与无符号右移的自己异或同时兼顾了hash高16位和低16位,让散列值更散。
3. 关注 get(Object key)
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final 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) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
- 可以看出,get()是拿着key的hash和key去找的值。
- 在getNode()中先是一系列判断和赋值,然后通过下标找定位到key在table中的位置
- 定位的方式:(n - 1) & hash,这样取出的值总是小于table长度n的。
- 然后对比key是否相等,相等就返回,不相等则判断是否是红黑树存储结构,若是则在红黑树上查找。
- 若不是则在链表结构上查找。
4.核心put(K key, V value)
public V put(K key, V value) {
return putVal(hash(key), key, value, false, 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)
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;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
//判断是否扩容
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
- 首先调用了putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict),
- 第一步做初始化工作。
- 然后,定位到table没有冲突,则直接存到table上。
- 若是冲突了,则判断key是否相等,若相等则,直接将旧德的Node覆盖。
- 否则,继续判断头节点是否是TreeNode的实例,TreeNode是一个红黑树,若是,则直接在树中插入。
- 如果不是红黑树,插到链表的尾部。
- 在hashmap中有一个属性为TREEIFY_THRESHOLD,这是一个阈值,若数量超过它,链表会转化为红黑树,小于它则会换回链表。所以hashMap同时用到了数组,链表,红黑树这三种数据结构。
- 每次新添一个节点都会判断是否需要扩容。
5. 扩容机制resize()
首先涉及三个成员变量:
- capacity:容量
- loadFactor:装载因子(0-1之间)
- threshold:判断是否需要扩容的标志threshold = capacity * loadFactor
- 所以装载因子控制着HashMap冲突比例。
- 每次扩容都扩大到之前的两倍。
- 扩容会重新建table等变量,因此开销比较大。
以上所述就是小编给大家介绍的《HashMap源码阅读小记》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【开发小记】 Java 线程池 之 被“吃掉”的线程异常(附源码分析和解决方法)
- Associated Objects 小记
- Flutter混合开发小记
- Associated Objects 小记
- Nginx配置小记
- 轩枫阁升级小记
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Design for Hackers
David Kadavy / Wiley / 2011-10-18 / USD 39.99
Discover the techniques behind beautiful design?by deconstructing designs to understand them The term ?hacker? has been redefined to consist of anyone who has an insatiable curiosity as to how thin......一起来看看 《Design for Hackers》 这本书的介绍吧!