HashMap浅析
HashMap是Java中最常用的数据集合,支持泛型K,V采用键值对的存储方式,主要的属性如下
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable,Serializable{
//默认的初始容量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//默认负载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//链表最大的长度,如果超过就会转换成树结构
static final int TREEIFY_THRESHOLD = 8;
//存放k,v的数据对象
transient Node<K,V>[] table;
//元素个数
transient int size;
//修改次数
transient int modCount;
//集合容量
int threshold;
//负载因子
final float loadFactor;
//内部链表类
static class Node<K,V> implements Map.Entry<K,V>{
final int hash;//key的hash值
final K key;//key
V value;
Node<K,V> next;//下一个对象
}
}
Map最的基本操作是put(k,v)和get(k)了
Map集合put
public V put(K key, V value){
return putVal(hash(key),key,value,false,true);
}
put函数会先调用hash函数获取到key的hash值,然后再调用putVal函数,hash(k)的核心是hash算法
static final int hash(Object key){
int h;
//取出高16位和hashCodeXORs操作
return (key == null) ? 0:(h = key.hashCode()) ^ (h >>>16);
}
获取到hash值后调用putVal存放k,v键值对
putVal
final V putVal(int hash,K key, V value, boolean onlyIfAbsent, boolean evict){
Node<K,V>[] tab; Node<K,V> p; int n,i;
if((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;//初始化tab ,n
if((p = tab[i = (n-1) & hash]) == NULL) //对hash桶长度求余计算hash对应的下标,然后
tab[i] = newNode(hash,key,value,null);//此位置位null直接创建
else{
Node<K,V> e; K k;
if(p.hash == hash &&
((k = p.key) == key) || (key != null && key.equals(k)))
e=p;//hash值相等,key为null或者key相等就替换p值
else if(p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this,tab,hash,key,value);//树结构就直接添加
else{
for(int binCount = 0;;++binCount){
if((e = p.next) == null){
//添加到最后一个
p.next = newNode(hash,key,value,null);
//如果链表结构大于8对hash桶进行扩容,如果容量不小于64就会转换为tree结构
if(binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab,hash);
break;
}
if(e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
//找到hash相同,key相同的位置返回,此时e的值就是需要存入Node结构体
break;
p = e;//指向下一个位置
}//end for
if(e != null){
//如果e不为null需要更新value的值
V oldValue = e.value;
if(!onlyIfAbsent|| oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}