直接上代码:
public V put(K key, V value) {
//如果key为null,存储位置为table[0]或table[0]的冲突链上
if (key == null)
return putForNullKey(value);
int hash = hash(key);//对key的hashcode进一步计算,确保散列均匀
int i = indexFor(hash, table.length);//获取在table中的实际位置
//如果i索引处的Entry不为null,通过循环遍历e元素的下一个元素
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
//如果该对应数据已存在,执行覆盖操作。用新value替换旧value,并返回旧value
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++;//保证并发访问时,若HashMap内部结构发生变化,快速响应失败
addEntry(hash, key, value, i);//新增一个entry
return null;
}
再看putForNullKey()这个函数的含义:
// putForNullKey()的作用是将“key为null”键值对添加到table[0]位置。
private VputForNullKey(V value) {
for(Entry<K,V> e = table[0]; e != null; e = e.next) {
if(e.key == null) {
VoldValue = e.value;
e.value= value;
e.recordAccess(this);
returnoldValue;
}
}
//如果没有存在key为null的键值对,则直接添加到table[0]处!
modCount++;
addEntry(0,null, value, 0);
returnnull;
}
而recordAccess()这个函数通过如下的源码知其并未进行操作。
// 当向HashMap中添加元素时,绘调用recordAccess()。
//这里不做任何处理
voidrecordAccess(HashMap<K,V> m) {
}
最后再看addEntry( )这个函数的操作:
// 新增Entry,将“key-value”插入指定位置,bucketIndex是位置索引。
void addEntry(int hash,K key, V value, int bucketIndex) {
//保存“bucketIndex”位置的值到“e”中
Entry<K,V>e = table[bucketIndex];
//设置“bucketIndex”位置的元素为“新Entry”,
//设置“e”为“新Entry的下一个节点”
table[bucketIndex]= new Entry<K,V>(hash, key, value, e);
//若HashMap的实际大小不小于 “阈值”,则调整HashMap的大小
if(size++ >= threshold)
resize(2* table.length);
}