您的位置:首页 > 其它

HashMap 基础原理以及源码解读

2017-08-15 15:52 483 查看
  第一次写博客,有理解或者表述不对的地方望博友指出,一起交流,一起进步。

  基础的数据结构,大家都不陌生, 基于 数组、链表之类 大家一定不陌生,今天咱们聊一聊他们的具体存储原理和效率。

数组 : 占用空间大,故空间复杂度大 ,但是数组的二分法查找时间复杂度小 ,查找容易,增加删除困难

链表 : 链表存储空间离散, 占用内存比较宽松,故空间复杂度很小,但时间复杂度较大 , 所以查找困难 ,增加删除容易

  以上两种数据结构效率均有所不如人意,哈希表就满足了查找容易,和增删容易

关于哈希表,最常用的实现就是拉链法-->也就是链表的数组

哈希表本身由数组+链表 组成,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。

HashMap是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。

看下HashMap的源码 jdk1.8可以发现  HashMap 的 put方法



final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;//n 数组长度 tab为数组
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)// 如果哈希值对应的值不存在,在数组对应位置新建数组 确定数组index
tab[i] = newNode(hash, key, value, null);
else {//否则确定数组index,对应位置新建链表
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)//如果size超过threshold,则扩充table大小。再散列
resize();
afterNodeInsertion(evict);
return null;
}
HashMap 的get方法源码部分(查找)
final Node<K,V> getNode(int hash, Object key) {//检查对应的哈希值是否一样,确定数组index  再根据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;
}
参考答案 http://blog.csdn.net/vking_wang/article/details/14166593
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: