浅谈HashMap
HashMap类
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
继承关系图
- 内部类HashMap.Node类:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next; //指向下一个(链表)
所有的key和value的数据都被封装在Map.Entry接口之中,此接口定义如下
interface Entry<K,V> {
比较重要的方法如下:有getKey()方法和getValue()方法
HashMap在存储数据增加到一定数量的时候(有一个阈值)就会由链表变为红黑树(类似于二分查找法,查找的性能更快)。
- 链表转为红黑树阈值:
static final int TREEIFY_THRESHOLD = 8;
- HashMap保存数据的个数的扩增是按照倍数(翻倍)进行的,这里有一个参考百分比。譬如(当前最大数据是16,参考条件是0.75,当数据量达到12时,数组增长一倍,变为32)
static final float DEFAULT_LOAD_FACTOR = 0.75f;
- HsahMap是支持异步处理的,但是有前提的。不能一边存一边读。譬如一边增加数据一边迭代数据。
常见问题
- HashMap中Hash冲突严重时会影响HashMap性能,如何解决。
在整个的Hash存储过程中,必须要明确两个实际的问题,hashcode()与equals()方法。如果hashcode()相同,这个时候会查询equals()方法,不过一般在使用Map的时候都会考虑使用String来实现。在String实现的Key里面是不存在这种复杂的问题的。这种问题只存在自定义的类里。所以当Hash冲突严重的时候,首先考虑equals()方法是否正常,那么在进行数据定位的时候会更加的快速。
但是如果从实际的数据结构的算法来讲,如果真的有哈希冲突那么就必须使用一些特定的处理方法
– 开放地址法:为一个哈希冲突求得一个地址序列。
– 链地址法:将所有哈希冲突的内容保存在一个链表里面。(HashMap的实现原理)
– 再哈希法:重新做一个hash计算。 - HashMap需要resize时扩容因子是如何得到的?
是通过判断,移位进行的,如果发现不够了,则进行移位处理。二进制的左移一位就是扩增一倍。