HashMap的读操作是O(1),写操作也是O(1)是这样的吗?
我们首先看put方法
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
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.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
HashMap允许一个key==null存在
当是null的时候之后从transient Entry[] table中获取index=0的值,然后更新旧的value
当不是null的时候先计算key的hash值,然后通过indexFor方法依据table.length获取具体的index值然后维护了一个Entry<K,V>链表,其有如下属性:
final K key;
V value;
Entry<K,V> next;
final int hash;
hash为key的hash值,value就是具体的值,next维护的是其链表,key就是具体的key值,判断是否key相同执行如下判断:
(e.hash == hash && ((k = e.key) == key || key.equals(k)))
也就是除了hash相同还需要key==或者equals
如果没有key相等的(参考上述条件),那么执行addEntry操作,如下:
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
也就是首先找table的bucketIndex,然后插入新增的链表,如果size值大于threshold,那么执行扩容操作,扩容,扩容操作需要重新往里面放值,那么就需要重新计算bucketIndex了,也就是执行indexFor方法:
static int indexFor(int h, int length) {
return h & (length-1);
}
依赖于具体key的hash值和现有table的length
总结:
HashMap实际上是维护了一个横向的数组,然后每个数组元素又是一个链表的头节点