HashMap结构
JDK1.7及之前:数组+链表
JDK1.8:数组+链表+红黑树
数组+链表
当数据通过put()方法插入时
会通过hash散列算法计算得出固定长度的数组下标——>
int hash = hash(key);
如果该数组下标对应的数据是null,则直接插入。如果有数值——>
1.7:头插法,通过改变头部节点的上节点指向
1.8:尾插法,通过改变尾部节点的下节点指向
由于HashMap属于线程不安全结构,那么如果多线程插入时扩容产生元素迁移则会导致原来a->b的指向,而迁移时重新计算索引位置有可能会导致b->a的情况产生,就变成了a->b->a…循环链。
原因:
e.next = newTable[i];
而1.8使用尾插法则在插入时直接插入到尾部,而HashMap扩容时是先赋值后扩容的方式,尾插时则不会导致循环链产生
插入时会通过hash散列先将key进行计算判断是否在数组中存在,如果
存在则通过key和value进行再次散列判断;
如果该数组不存在hash碰撞,则判断该数组下是否是null;
如果是,则newNode追加节点插入链表;
如果不是,则判断是否是红黑树;
如果不是,则判断长度是否不小于8;
如果小于8则追加节点,如果不小于8,则触发扩容
当数据通过get()方法查询时
同样会通过hash散列算法获取数组下标,然后通过数组下标查询到对应的数组,如果该数组下有一链表,那么通过key进行遍历判断获取对应的数据。
通过key计算hash值
判断HashMap的数组是否为null和数组长度是否为0,如果为null和0则直接返回null
如果不为null和0,计算key的下标,判断第一个node是否是对应数据,如果是,则直接返回数据
如果不满足条件,判断是否是最后一个节点node,如果是,则返回null
如果不是最后一个node,判断是否是红黑树,如果是红黑树,则通过hash值判断进入红黑树获取key
如果不是红黑树,遍历链表判断是否有满足的条件,有则直接返回,无则返回null