一、数据结构
java集合主要是两个接口中衍生而来。一个是Collection,另一个就是是Map。两个接口都来自java.util包。HashMap实现了Map接口,其底层是数组加单链表的方式进行存储的。
具体来说,在执行put(key,value)方法后,先key的hash值。通过key.hashCode()方法 后在经过扰动函数得到hash值。(数组长度 - 1) & hash后得到数组的下标。若该位置为空,则直接放入;若该位置不为空,则需要比较他们的hash值。若与某个相同,则再用equals方法比较他们的地址值是否相等。若为false则采用拉链法解决哈希冲突,为true则替换该位置的value值。
二、方法
1、put方法
package com.tyz.hashmap;
public class HashMap<K,V> {
static final int hash(Object key){
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key,V value){
return putVal(hash(key),key,value,false,true);
}
final V putVal(int hash,K key,V value,boolean onlyIfAbsent,boolean evict) {
Node<K, V>[] tab;
Node<K, V> p;
int n, i;
//判断是否为空,为空就初始化,不为空就对tab和n进行赋值
if (tab == null) {
n = (tab = resize()).length;
}
//根据hash值计算出数组下标位置
//如果该位置为空,则直接赋值
if ((p = tab[i = (n - 1) & hash]) == null) {
tab[i] = newNode(hash, key, value, null);
//如果不为空,则需要判断二者的hash值和key是否相等
} else {
Node<K, V> e;
K k;
if (p.hash == hash && ((k == p.key) == key || (key != null && key.equals(k)))) {
//如果相等则覆盖原值
e = p;
} else {
//二者不相同,则但是数组中已经有value了,所以需要遍历单链表进行尾插。
for(int binCount = 0;;++binCount){
if((e = p.next) == null){
p.next = newNode(hash,key,value,null);
break;
}
if(e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))){
break;
}
p = e;
}
}
//这种属于覆盖操作,当e中有值进入操作
if (e != null) { // existing mapping for key
//oldValue保存老的值,方便return
V oldValue = e.value;
//onlyIfAbsent传入的是false,指定能进入判断
if (!onlyIfAbsent || oldValue == null)
//新元素的值将老元素的值覆盖掉
e.value = value;
//HashMap提供给子类的方法
afterNodeAccess(e);
//put操作有返回值,返回的是插入之前已经存在的元素的value值
return oldValue;
}
}
//增加修改次数
++modCount;
if(++size > threshold){
resize();
}
afterNodeInsertion(evict);
return null;
}
}