HashMap基本知识
- 链表数组,使用散列函数定位位置,链表的元素是Entry< key,value>
- 查询性能O(1),增删性能O(1)
- 非线程安全,使用modCount字段实现快速失败的功能
- 在table长度小于阈值(1 << 30)的情况下,能够自动扩容
- 定位的算法:
- 取key.hashCode进行hash函数运算,得出运算结果h
- 将h和table.length进行计算:h & (table.length - 1)
- 取table[index] 的链表,对key进行比较(hash值的比较,equal比较)
- 4个构造函数
- 使用默认 table大小和loadfactor
- 指定table大小
- 指定loadfactor
- 使用存在的HashMap
问题总结
- 能否存储key为null的元素?
可以,存在table[0]的链表里 - HashMap啥时候resize table?
当map中元素的总数量size大于threshold - loadfactor的作用
- threshold 的作用
threshold = (int)Math.min(table.length * loadFactor, MAXIMUM_CAPACITY + 1);
用来控制hashMap中元素的总数量。当总数量size大于threshold 的时候,就需要进行扩容操作了。
主要源码
get方法:
get(key){
hash = hash(key.hashcode()); //计算出key的hash函数结果
for(Entry<k,v> e:table[indexForKey(hash,table.lenght) ; e!=null ; e=e.next()]){
if(hash == e.hash && ((k = e.key) == key || (k != null && k.equal(key)))){
return e.value;
}
}
return null;
}
put方法:
定位方法类似get。找到位置,且没有相同的key的情况下。新增一个,如果key相同就替换原来的value
涉及到table大小的调整
put(key,value):
if(table == EMPTY_TABLE)
{
inflateTable(threshold);
}
if(key == null){
return putForNullKey(value);
}
int hash = hash(key.hashcode()); //计算出key的hash函数结果
int index = indexFor(hash,table.length);
for(Entry<k,v> e:table[indexForKey(hash,table.lenght) ; e!=null ; e=e.next()]){
if(hash == e.hash && ((k = e.key) == key || (k != null && k.equal(key)))){
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash,key,value,index);
return null;
addEntry():