对于JDK 1.7 来说,HashMap的结果就是 数组+链式 的结构;
具体来说:对于put方法:
public V put(K key, V value) {
if (table == EMPTY_TABLE) { //首次开始的时候,Entry<K,V>[] 为空
inflateTable(threshold); //初始化HashMap的Entry<K,V>[] 数组,默认容量(threshold= capacity * loadFactor)是16;
}
if (key == null)
return putForNullKey(value); //保存key为null 的键值对-->1
int hash = hash(key); //获取key的hash值-->3
int i = indexFor(hash, table.length); //hash值与Entry[]的长度做&运算结果作为元素落在Entry[]上的下标
for (Entry<K,V> e = table[i]; e != null; e = e.next) { //找到下标所在的元素Entry,遍历Entry的链后面的元素next
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //如果存在相同的key就替换掉,并返回就value
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i); //当该下标不曾被暂用,不存在元素是,就直接去新增Entry下标为i的元素
return null;
}
--->1:
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) { //对于key为null的情况,默认遍历第一个数组及下面的链;
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0); -->2 增加Entery[]的元素
return null;
}
-->2:
void addEntry(int hash, K key, V value, int bucketIndex) { //
if ((size >= threshold) && (null != table[bucketIndex])) { //判断是否大于容量值threshold
resize(2 * table.length); //如果大于扩展容量是原来的2倍
hash = (null != key) ? hash(key) : 0; //获取key的hash值,key为null的hash是0
bucketIndex = indexFor(hash, table.length); //得到元素在Entry[]数组中的位置下标
}
createEntry(hash, key, value, bucketIndex); //对于key为null直接创建元素,在这创建了
}
-->3:
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
对于get方法:
public V get(Object key) {
if (key == null)
return getForNullKey(); //对于key是null的情况,直接取Entry[0]位置的元素(JDK1.7)
Entry<K,V> entry = getEntry(key); --->4
return null == entry ? null : entry.getValue(); //直接返回
}
--->4:
final Entry<K,V> getEntry(Object key) {
if (size == 0) {return null;
}
int hash = (key == null) ? 0 : hash(key); //获取key的hash值
//获取hash对应的下标,并找出下标对应的元素,然后遍历Entry节点所在的链,直至找到hash相等且equal的元素并返回e
for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {Object k;
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}