HashMap浅析

来源:互联网 发布:淘宝卖家自动回复语 编辑:程序博客网 时间:2024/06/05 00:50

首先来看,HashMap实现了自己的entry: Node<K,V>
内部变量有:
final int hash;
final K key;
V value;
Node<K,V> next;

HashMap内部变量:
Node <K,V>[] table
int size
int modCount
int threshold
final float loadFactor
Set<Map.Entry&ltK,V>> entrySet
transient volatile Set<K> keySet;
transient volatile Collection<V> values;

构造方法:
HashMap(int initialCapacity, float loadFactor)
先检查参数是否合法,loadFactor赋值,threshold必须为2的多少次方,且设置为仅大于initalCapacity.
HashMap(int initialCapacity)
调用上一个构造方法,loadFactor为默认值
HashMap()
loadFactor为默认值,这个构造方法threshold为0


关键方法:
int hash(object)
这个方法把object的哈希值的高16位和低16位异或,结果放入低16位,高16位保留

V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)
如果还没初始化数组,就初始化一个
接着把key的hash值和数组的长度-1进行与操作,得到的结果作为数组的下标
如果这个位置并没有元素,那就new一个Node放进去
如果已经有元素,前面看到HashMap实现了自己的entry,entry里面有next,因此会形成一个链表. 接下来会对链表进行逐个比对,直到找到Key相同的或到了尽头, 那么key相等需要满足2个条件:1 hash值要相等 2 key的内存地址相同或equals返回true. 如果找到key,还要看onlyIfAbsent变量决定是否刷新value;如果到了尽头,那就直接new一个Node
最后size变量+1,再看是否需要扩容
java8新加入: 当链表中数量达到8个时,会把链表转换成红黑树结构,加快查找速度;

Node<K,V> getNode(int hash, Object key)
这个方法和插入方法的查找差不多

Node<K,V>[] resize()
1:当map已经初始化但未放入任何元素时: 如果threshold为0(无参构造),则新容量为默认初始容量,新threshold为默认loadfactor*默认初始容量; 如果threshold不为0(构造传入),新容量为threshold. 最后table赋值为新容量的Node数组
2:当map中已经有元素: 把容量和threshold都扩大两倍,然后就要把旧数组的元素移动到新数组.
看看具体怎么移动: 容量变为2倍,转为二进制就是多了一位,那么hash & 容量-1也会多出一位,那么用这多出的一位来决定这个entry是在table的上部还是下部. 开始移动,遍历每一个链表,用刚才提到的方法,分散每一个entry,可以看到这样就把链表缩短了

接下来要看如何遍历内部:
内部abstract class HashIterator
其内部成员:
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index;

构造:获取当前hashmap里的table,顺着数组移动到第一个entry,next变量会指向它. 如果没有entry,则next为null
hasNext: 判断next变量是否为null
取下一个:current指向next,然后判断next的下一个存不存在,如果存在那就后移一位; 如果不存在,那就顺着数组往下找
在HashMap内有个内部变量entry,在调用entrySet()方法时,会先检查这个变量是否为null,若不为null,则返回这个变量; 若为null,则new一个Set,这个Set的iterator()方法返回 一个新的HashIterator

KeyIterator ValueIterator都继承 HashIterator ,因此keySet()和values()方法都是类似的

0 0
原创粉丝点击