您的位置:首页 > 其它

HashMap:HashMap学习笔记

2019-08-01 07:17 1636 查看

一、hash算法

// jdk中hash方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

// hashMap中执行putVal的方法,截取一小段
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);

例如:
// 取hash值,并转换为二进制
int h = "test".hashCode();
System.out.println(Integer.toBinaryString(h));

// 将hash值右移16位
int nh = h >>> 16;
System.out.println(Integer.toBinaryString(nh));

// 获得h与nh的异或的值
int hash = h ^ nh;
System.out.println(Integer.toBinaryString(hash));

输出
1101100100010010010010
110110
1101100100010010100100

32位补全整理之后
hashCode        0000 0000 0011 0110 0100 0100 1001 0010
右移16位后       0000 0000 0000 0000 0000 0000 0011 0110
前面两个值异或    0000 0000 0011 0110 0100 0100 1010 0100
  • 先将传入的值取hashCode值,记作h
  • 再将h右移16位,记作nh
  • 最后将h与nh进行异或就是最终结果hash
  • 将hash与15相与(即取模)获得索引位置index

二、Java8 HashMap存入的源码注释

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;
// 判断当前数组是否已经进行了初始化
// tab是当前Node数组
if ((tab = table) == null || (n = tab.length) == 0)
// 如果没有初始化,则初始化,扩充数组
n = (tab = resize()).length;
// 表示当前index位置没有存储位置
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
// 表示索引的坑位被占用
else {
HashMap.Node<K,V> e; K k;
// 判断当前的key是否存在,如果存在,则覆盖
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 判断是否是红黑树,则往树里插入元素
else if (p instanceof HashMap.TreeNode)
e = ((HashMap.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);
// 如果链表长度大于等于8,则将链表转换成红黑树
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;
}
}
// 迭代器 failfast 快速失败
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

三、HashMap的组成

在jdk8以前(不包含jdk8),HashMap是由数组与链表构成,而在jdk8做了改动,当链表的元素大于等于8个时候,则将链表改造成红黑数,目的是为了追求稳定,无论是增删查,他的时间复杂度趋于稳定,都是O(logn)

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: