1.HashMap的数据结构:
哈希表结构(链表散列:数组+链表)实现,有数组和链表的优点,在链表长度超过8时,链表转换为红黑树。数组类型是Entry,Entry存储键值对,它包含四个字段,final K key, V value, Entry<K,V> next, int hash,可看出Entry是一个链表,数组中的每一个位置被当成一个桶,一个同放一个链表,使用拉链法(1.7之前头插,1.8尾插)解决冲突,同一个链表存哈希值相同的Entry。
2. HashMap的工作原理:
底层是hash数组和单向链表实现,数组中每个元素为链表,有Node内部类(实现Map.Entry<K,V>接口)实现,通过put,get存取。
存储对象:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
// 键为 null 单独处理
if (key == null)
return putForNullKey(value);
int hash = hash(key);
// 确定桶下标
int i = indexFor(hash, table.length);
// 先找出是否已经存在键为 key 的键值对,如果存在的话就更新这个键值对的值为 value
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;
}
将K/V键值传给put()方法:1)调用hash(K)方法计算K的hash值,然后结合数组长度,计算数组下标;2)调整数组大小(当容器元素个数大于capacity*loadfactor时,容器会进行扩容2n);3)如果K的hash值在HashMap中不存在,则执行插入,若存在,则发生碰撞,若存在且二者equals返回true,则更新键值对,若存在但是二者equals不等,则插入链表尾部或者红黑树中。
HashMap 允许插入键为 null 的