Java Jdk1.8 HashMap源码阅读笔记(一)(2)

2019-09-02 12:53

这也正好解释了为什么HashMap底层数组的长度总是 2 的 n 次方。因为这样(数组长度-1)正好相当于一个“低位掩码”。“异或”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。

以初始长度16为例,16-1=15。

2进制表示是00000000 00000000 00001111。

和某hash值做“异或”操作如下,结果就是截取了最低的四位值。 ```

10100101 11000100 00100101 00000000 00000000 00001111 ----------------------------------

00000000 00000000 00000101 //高位全部归零,只保留末四位

更详细的步骤如下: 这里写图片描述

2、获取元素 /**

* Returns the value to which the specified key is mapped,

* or {@code null} if this map contains no mapping for the key. *

*

More formally, if this map contains a mapping from a key

* {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) *

*

A return value of {@code null} does not necessarily * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. *

* @see #put(Object, Object) */

public V get(Object key) { Node e;

return (e = getNode(hash(key), key)) == null ? null : e.value; }

/**

* Implements Map.get and related methods *

* @param hash hash for key * @param key the key

* @return the node, or null if none */

final Node getNode(int hash, Object key) { Node[] tab; Node first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && //hash & length-1 定位数组下标 (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) {

//第一个节点是TreeNode,则采用位桶+红黑树结构, //调用TreeNode.getTreeNode(hash,key), //遍历红黑树,得到节点的value if (first instanceof TreeNode)

return ((TreeNode)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; }

树节点的查找:

/**

* Calls find for root node. */

final TreeNode getTreeNode(int h, Object k) { return ((parent != null) ? root() : this).find(h, k, null); } /**

* Finds the node starting at root p with the given hash and key. * The kc argument caches comparableClassFor(key) upon first use * comparing keys.

*通过hash值的比较,递归的去遍历红黑树,

compareableClassFor(Class k):判断实例k对应的类是否实现了Comparable接口,如果实现了该接口并

在某些时候如果红黑树节点的元素are of the same \C implements

Comparable\

*利用他们的compareTo()方法来比较大小,这里需要通过反射机制来check他们到底是不是属于同一个类,是不是具有可比较性.

*/

final TreeNode find(int h, Object k, Class kc) { TreeNode p = this; do {

int ph, dir; K pk;

TreeNode pl = p.left, pr = p.right, q; if ((ph = p.hash) > h) p = pl; else if (ph < h) p = pr;

else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if (pl == null) p = pr;

else if (pr == null) p = pl;

else if ((kc != null ||

(kc = comparableClassFor(k)) != null) && (dir = compareComparables(kc, k, pk)) != 0) p = (dir < 0) ? pl : pr;

else if ((q = pr.find(h, k, kc)) != null) return q; else

p = pl; } while (p != null); return null; }

四、小结

在创建 HashMap 时根据实际需要适当地调整 load factor 的值;如果程序比较关心空间开销、内存比较紧张,可以适当地增加负载因子;如果程序比较关心时间开销,内存比较宽裕则可以适当的减少负载因子。通常情况下,程序员无需改变负载因子的值。

如果开始就知道 HashMap 会保存多个 key-value 对,可以在创建时就使用较大的初始化容量,如果 HashMap 中 Entry 的数量一直不会超过极限容量(capacity * load factor),HashMap 就无需调用 resize() 方法重新分配 table 数组,从而保证较好的性能。当然,开始就将初始容量设置太高可能会浪费空间(系统需要创建一个长度为 capacity 的 Entry 数组),因此创建 HashMap 时初始化容量设置也需要小心对待。

1.8中的HashMap类代码大约2000多行,此处只挑选了插入、获取元素两个比较重要

的点,先阅读记录一下,后续有时间继续更新。


Java Jdk1.8 HashMap源码阅读笔记(一)(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:中国共产党成都市第一次代表大会

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: