目录
一、 HashMap的数据结构
1.7版本与1.8版本数据结构的区别
1.7版本使用的数据结构是数组 + 链表的形式。对于新增的节点使用的是头插法,新增的节点增加在离桶最近的地方。
1.8版本使用的是 数组 + 链表/红黑树的形式。新增节点使用的是尾插法,新增的节点在链表的尾部。当链表的长度>=8时,会转换为红黑树结构。
二、HashMap的功能实现源码解析
1. hash方法
如果没有指明HashMap的初始化大小值,则其默认初始化大小是16。
当我们有一个新的值被put方法放入HashMap时,它应该在0~15之间有一个具体的位置。那么应该用什么方法确定它的位置呢?
我们常想到的就是用随机取模的方法来做,Random(16).nextInt(),简单粗暴。但是如果我们对同一个key比如"hello",反复地放入同一个HashMap,则其每次的位置都是随机的且位置不同,这样对于查找并不方便,最好用一种与key本身带有某种关系的算法,同一个key往往放在同一个位置。我们看下HashMap的源码是怎样确定key的位置的。
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 {
....
}
}
源码的算法是 tab[i = (n - 1) & hash]
tab是HashMap内部的Node数组,tab[i]就是第i个的位置。 i 的取值是(n-1) & hash。
n -1 是数组的长度 - 1, 那么hash是什么呢?
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
它的计算原理是: ha