JDK 1.8 HashMap 源码阅读二
2017-03-11 12:40
507 查看
HashMap中对key的hashcode再处理
由上篇文章我们已知HashMap的寻址是让key的hashcode与bucket长度取模。如果bucket长度为16,即只有hashcode的低四位参与了寻址。这大大加大的碰撞的发生。HashMap中为了让碰撞几率减小,让hashcode更多位参与寻址。他做了如下处理:
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }即key的hashcode保留高16位,低16位的值为高16位与低16位的异或值。 这样处理,让hashcode的高16在bucket长度小的情况下也能参与寻址以减小碰撞的可能。
HashMap中Get方法的实现
其Get方法是通过Key值来获得对应的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的hashcode方法和equals方法。自定义类作为key时,需要实现这两方法。
-Get方法在取value后,并没有删除该键值对。即插入键值对,若无手动remove,可重复取用。
-Get方法并未过滤key为null的情况,同时也未应用到value的值。即支持key/value为null的情形。
HashMap中删除键值对
JDK中提供了2中删除方式:public V remove(Object key) { Node<K,V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; }以及
@Override public boolean remove(Object key, Object value) { return removeNode(hash(key), key, value, true, true) != null; }从中可以看出,不同处是方法一只对key做关键字删除,而方法二是同时推键值对做关键字删除。
但是其底层实现是同一函数的,只是参数不同而已。
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; } 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).removeTreeNode(this, tab, movable); else if (node == p) tab[index] = node.next; else p.next = node.next; ++modCount; --size; afterNodeRemoval(node); return node; } } return null; }由上代码可知,其主要分为2个步骤,查找和删除。
其查找的实现就是Get方法的实现,而删除的操作就是从链表中摘除掉一个节点,或从红黑树中摘除一节点。
最后的说明
本人对HashMap的阅读并未深入到树形存储部分,因为红黑树的算法实现和结构是另一回事了,如要说明又是一篇很长的篇幅。同时在阅读HashMap的源码时,我并未看到其有多线程的同步操作处理。即HashMap是非线程安全的。
需要线程安全,可以考虑HashTable和ConCurrentHashMap。
相关文章推荐
- Java Jdk1.8 HashMap源码阅读笔记一
- jdk 1.8 hashmap resize 源码阅读
- Java Jdk1.8 HashMap源码阅读
- Java Jdk1.8 HashMap源码阅读笔记二
- JDK 1.8 HashMap 源码阅读一
- [Jdk1.8源码阅读]ArrayList
- JDK1.8 HashMap源码分析
- jdk 1.7 1.8 HashMap 源码分析
- WeakHashMap源码探讨(基于JDK1.8)
- 【JDK1.8】JDK1.8集合源码阅读——LinkedHashMap
- JDK源码阅读——HashMap(1.7)
- JDK源码阅读之 HashMap
- JDK 1.8 ArrayBlockingQueue 源码阅读(二)获取
- HashMap源码探讨(基于JDK1.8)
- 浅析 jdk1.8源码之HashMap
- HashMap源码分析(JDK 1.8)
- 【jdk1.8】HashMap源码分析
- 阅读jdk1.8源码小收获
- HashMap源码解析(JDK1.8)
- jdk源码阅读-HashMap