版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiaojun1234567/article/details/82191461
HashMap的工作方式
HashMap 是怎样哈希的呢?
HashMap内部有一个Entry数组,大概这个样子
static class Entry<K,V> implements Map.Entry<K,V>{
final K key;
V value;
Entry<K,V> next;
final int hash;
}
因此,HashMap并不是以键值对的方式存储,而是以数组形式的存储?那么它是如何做到O(1)的效率的呢?
这就需要了解散列的知识,也就是 哈希散列
。
就是要把我们的 key 与数组索引(0, 1, 2,3,4..)做一个映射,让我们来看看HashMap
put()方法的实现
public V put(K key, V value) {
if (key == null) {
return putForNulllKey(value);
}
int hash = hash(key.hashCode);
int i = indexFor(hash, table.length);
// 遍历 i 号桶
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && (k = e.key) == key && key.equals(k)) {
V oldValue = e.value;
e.value = value;
e.recordAcess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value,i);
return null;
}
- 首先检查所给的键值key是否为
null
,如果是null
,那么它将会被存储在0号位置。因为null
的hashcode值就是0 - 通过 key. hashCode() 的key对应的hashCode值,为了让所得到的hash值限制在数组索引范围内,调用hash(key.hashCode()),在这里面将会做一些位移运算。
- indexFor() 方法得到在Entry数组中的确切位置
- 这里是最重要的部分,如果两个key具有相同的hashCode怎么办?将会存储在相同的桶里面,这里的桶实际上是一个链表结构。所有具有相同hash值的键值都会存储在同一个链表里,并且通过equals()比较键是否相等。