HashMap学习笔记一
1.Hashmap的概述:
Hashmap是基于哈希表的Map的接口的非同步实现。此实现提供所有可选的映射操作,并且运行使用null键和null值。此类不保证映射的顺序,特别是不保证顺序的恒久不变。
2.Hashmap的数据结构:
链表与数组的结合体
源码:
transient Entry[] table;
static class Entry<K,V> implements MAp.Entry(){
final K key;
V value;
Entry next
final int hash;
...........
}
可以看到,Entry就是数组中的元素,每个Map.Entry就是一个key-value,它持有指向另一个元素的引用。这就构成了链表;
3.Hashmap的存取实现
存储代码
public V put(K key,V value){
//hashmap允许null键和null值
//当key为null的时候,就调用 putForNullKey(),将value放置在数组的第一个位置
if(key == null)
return putForNullKey();
//根据key的keyCode重新计算哈希的值
int hash = hash(key.hashcode());
//搜索指定的值在table中的索引
int i = indexFor(hash,table.length());
//如果索引i处的Entry不为null,则遍历e元素的下一个元素
for(Entry<K,V> e = table[i];e != null;e = e.next){
Object key;
if(hash == e.hash && (key = e.key) == key ||key.equal(key))){
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//操作数加一
modCount++;
//将key,value添加到索引处
addEntry(hash,key,value,i);
return null;
}
从上述源码中可以看出,我们往HashMap中put元素的时候,新根据key的hashCode重新计算hash值,根据哈希值获取这个元素在数组中的位置,如果数组上已经有元素则以链表的形式存放
addEntry(int hash,K key,V value,int bucketIndex){
//获取指定bucketIndex处的Entry
Entry<K,V> e = table[bucketIndex];
//将新创建的Entry放入bucketIndex索引处,新Entry指向原来的Entry
table[bucketIndex] = new Entry<K,V>(hash,key,value,e);
//map中key-value对象是否超过指定的数目
if(size++ > threshold){
//table对象扩展到原来的两倍
resize(z*table.length());
}
}
所以当存储HashMap中的key-value的时候完全没有考虑Entry中的value,仅仅根据key来计算Entry的存储位置,完全可以吧value看着key的附属。
hash(int h)根据hashCode重新计算一次散列,此计算加入了高位算法,防止低位不变高位变化的时候发生哈希冲突。
static hash(int h){
h ^ = (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
调用indexFor(int h,int length)来计算该吧对象保存再table数组的那个位置的索引
public static int indexFor(int h,int length){
return h&(length - 1);
}
因为hashmap的长度总数为2的n次方,所以使用h^(length-1)算法可以对HashMap的速度进行优化。
HashMap的构造器包含的代码
int capacity = i;
while(capacity < initailCapacity)
capacity < 1;
上述代码保证了HashMap数组的大小总是2的n次方,h&(length-1)等价于h%length。&bi%高效
总结:
根据put的源码分析可以知道,当程序试图将key-value放入hashmap中,会根据key的hashcode(),决定Entry的存储位置;如果key的hashcode值相同,那么他们的存储位置相同。如果key的equal()返回为true
则新的value覆盖老的value。如果key返回为false,则形成Entry链表存储。

浙公网安备 33010602011771号