先上源码:node
public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
咱们都知道hashMap底层数据结构为:数组+单项链表+红黑树;算法
获取一个value值首先要获取当前key值所在的节点,获得该节点 e.value属性值即为目标值;数组
第一步:对key值进行hash运算,获得节点位置;(如何hash运算:获取key值得hashcode将其称为h值,而后对该h值>>>16无符号右移16将其称为h16,而后对这两个值进行异或运算 h^h16)。hash运算要通过三个步骤才能算出节点位置。数据结构
第二部:getNode(h,key); 有告终点位置,咱们就能够进行下一步的运算;h即为数组的下标;spa
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; }
这个方法中有5个局部变量:code
Node<K,V>[] tab;//hashmap中数组get
Node<K,V> first, e;//目标节点的第一个元素、目标节点元素源码
int n; //数组长度hash
K k;//目标节点的key值table
为何要传两个值(int hash, Object key):存在hash冲突!
第一个if判断:知足三个条件 ->数组不为空 && 数组长度>0 && 目标节点存在 ;
若是知足这三个条件,能够获得一个数组元素,目标值即存在该元素之中;
第二个if判断:知足两个调节-> 第一个元素节点的下标与目标节点的下标一致&&key值一致;
这种状况存在当前数组元素只有一个节点,直接返回该数组元素值;
第三个if判断:第二if不知足时,表示该值存在一个链表中;
首先判断当前结点是否为红黑树,若是是红黑树,则进行红黑树取值操做;
若是是链表,便利链表获取目标值;
总结:hashmap底层是数组+链表+红黑树;获取value值总而言之就是经过key值hash运算、无符号位移运算以及异或运算得到数组下表位置;
获得数组元素目标数据以后,便可获得一个链表,判断该链表第一个节点值是否为所求值,若是是直接返回,不是的话判断是否为红黑树,若是是红黑树,
红黑树算法遍历求值;非红黑树,则do...while遍历链表;
ps:语言表达不是很准确,望指正;