用法
package datastructure;
import java.util.HashMap;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put("1","1");
map.get("1");
}
}
构造函数
- 不传参数的话,默认长度16,加载因子也就是扩容因子为0.75
- 如果传入的是2^n的话,则不变,如果传入的不是,则把cap转为比自己小的2的n次方,是为了扩容、计算数组下标等直接使用位运算方便
- 第二个参数是扩容因子,可以自定义
HashMap<String,String> map = new HashMap<>();
HashMap<String,String> map1 = new HashMap<>(1);
HashMap<String,String> map2 = new HashMap<>(1,0.75f);
put方法
存入数据简单操作流程
resize() 方法
计算hash值:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
计算数组下标:
//n为数组长度
i = (n - 1) & hash
再看看搬运到新数组的hash计算
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
总结一下,这个设计非常巧妙。上述中,
has&(cap-1)相当于hash%cap进行取余,
hash&cap==0相当于此数hash小于cap
那么,接下来,如果hash比原数组小,则移到新数组,下标不变
如果hash比原数组大,则移到新数组,下标变为 老数组下标+老数组长度
如果接下来再有数据进入,就进入到扩容之后的数组中,使用has&(cap-1)获取数组下标时,cap就变为了新数组的长度,那么下表恰好为修改之后的数组下标
树转为为链表
只有在resize方法中才会操作树转化为链表
在resize中,如果是树节点,则判断节点是否**<=6**,如果是,则树转化为链表
remove方法
直接移除节点,如果是红黑树,则对树进行操作,但是不会进行转化为链表操作
itreator遍历
快速失败,如果在遍历的过程中,map的个数有变动,则快速失败
int expectedModCount; // for fast-fail
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}