您的位置:首页 > 编程语言 > Java开发

HashMap集合put函数源码阅读记录

2018-03-01 00:00 288 查看
在阅读put函数源码前,首先看看会用到的几个变量

/**
* 用于记录HashMap集合中增、删、改的次数
* 该值会在初始化迭代器时存储在一个局部变量expectedModCount中
* 由于HashMap不是线程安全的,因此在使用迭代器时,如果有其它线程修改了map,会造成modCount的值与expectedModCount不一至,将会抛出ConcurrentModificationException异常
*/
transient int modCount;

/**
* 用于表示key为空的条目
*/
transient HashMapEntry<K, V> entryForNullKey;

/**
* HashMap集合大小的阈值
*/
private transient int threshold;

首先看Map集合中最常用的 put(K key, V value) 函数

/**
* Maps the specified key to the specified value.
*
* @param key
*            the key.
* @param value
*            the value.
* @return the value of any previous mapping with the specified key or
*         {@code null} if there was no such mapping.
*/
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
// 计算key的hash值
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
// 根据hash值计算存储的位置
int index = hash & (tab.length - 1);

// 循环偏历entry数组,判断key对应的entry是否存在,如果对应的entry已经存在,则直接将旧的entry.value修改为新的value,并且返回旧的value
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
// 判断hash、key值是否完全都相同
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}

// No entry for (non-null) key is present; create one
modCount++; // 记录修改次数
// 判断当前map集合的长度是否超出阈值
if (size++ > threshold) {
// 扩容,并且重新生成Hash表
tab = doubleCapacity();
// 根据新生成的hash表重新计算存储的位置
index = hash & (tab.length - 1);
}
// 创建对应的entry数据并保存在对应的存储位置
addNewEntry(key, value, hash, index);
return null;
}

当存储的key值为null时会调用putValueForNullKey(V value),当key值不为空的情况见注释,putValueForNullKey函数代码如下

private V putValueForNullKey(V value) {
HashMapEntry<K, V> entry = entryForNullKey;
if (entry == null) {
addNewEntryForNullKey(value);
size++;
modCount++;
return null;
} else {
preModify(entry);
V oldValue = entry.value;
entry.value = value;
return oldValue;
}
}

在这里判断了,当entry为空时,会先调用addNewEntryForNullKey()函数,调用该函数创建一个HashMapEntry对象,新创建出来的HashMapEntry被entryForNullKey所引用。

当entry不为空时,说明之前已经存在一个entryForNullKey的引用,则直接将旧的value替换成新的value,并且返回旧的value值。

/**
* Creates a new entry for the null key, and the given value and
* inserts it into the hash table. This method is called by put
* (and indirectly, putAll), and overridden by LinkedHashMap.
*/
void addNewEntryForNullKey(V value) {
entryForNullKey = new HashMapEntry<K, V>(null, value, 0, null);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 Java