一、存储数据解析
1、先看put方法
public V put(K key, V value) {
//如果key值为空,调用putForNullKey方法存储键值对,点进该方法中,可以看到,调用的addEntry方法默认会将内容存到数字下表为0的链表下
if (key == null)
return putForNullKey(value);
//根据key计算并获取hash值
int hash = hash(key);
//根据hash值与链表长度获取所存数据应存放的数组下标
int i = indexFor(hash, table.length);
//如果该下标在数组中已经存在数据,那么就会循环遍历链表下的数据
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//解决hash冲突,如果链表中的key值一样,则新的value值会覆盖原来的oldValue值
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
//如果,存在hash冲突,且链表中的key没有重复,那么就新增一个entry在该链表上
addEntry(hash, key, value, i);
return null;
}
2、addEntry方法
void addEntry(int hash, K key, V value, int bucketIndex) {
//如果集合存储长度>=(容量*负载因子 16*0.75,因为数组初始值为16,所以threshold初始值为12)且当前下标对应的值不为空,则需要扩容
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
//继续创建entry值
createEntry(hash, key, value, bucketIndex);
}
3、createEntry方法
void createEntry(int hash, K key, V value, int bucketIndex) {
//将旧的链表赋值给entry的next,即extry的next地址指向之前的链表
Entry<K,V> e = table[bucketIndex];
//把之前的链表接到当前要存储的entry后面
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
二、获取Map中数据
1、先看get方法
public V get(Object key) {
//如果key值为空,直接通过getForNullKey方法获取value值
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key);
//如果获取到的entry不为空,这返回该entry的value值
return null == entry ? null : entry.getValue();
}
2、getEntry方法
final Entry<K,V> getEntry(Object key) {
//获取key的hash值
int hash = (key == null) ? 0 : hash(key);
//如果通过hash值与数组长度计算的下标存在链表,且不为空,则遍历该链表
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
//如果hash值与key都相等的话,则返回entry值
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
//都找不到,自然返回空了
return null;
}