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 (Entrye = 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;Entrynext;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) { Entrye = table[bucketIndex]; table[bucketIndex] = new Entry (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实际上是维护了一个横向的数组,然后每个数组元素又是一个链表的头节点