目录
HashMap
hashmap的组成是数组+链表+红黑树
当我们创建一个HashMap时,它会先自己定义一个加载因子0.75f(默认值),该加载因子的大概意思是当我们存储的数据达到了它的数组百分之75的时候的时候就会扩容,为什么不是存满了再扩容呢?因为它还有一个链表结构,比如它可能存储到百分之90的时候就把数据一直挂在链表上(hash冲突)导致链表过长并提前转成红黑树,因此就需要设置一个阀值,那为什么不是百分之50或者百分之30就扩容,那样会导致内存的浪费。
当我们调用put(key,value)方法添加数据时,它会先用hash(key)进行哈希运算计算哈希值,尽量减少哈希碰撞。
具体实现的putVal()方法,它会先创建一个Node类型的数组主要存储hash值、数据和下一个数据。
然后进行判断是不是需要初始化容量,然后调用resize初始化容量大小为16。
然后在查看hash值所在的节点是否为空(是否有值),为空则将数据存入该节点。
不为空则进行hash值的比较,再进行key值的比较 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))如果都相等就会通过e标记然后进行替换。
否则比较是否树的节点p instanceof TreeNode,是则放入树中。
否则遍历链表的for (int binCount = 0; ; ++binCount)并查找链表的尾节点if ((e = p.next) == null),Node的next是存储下一个数据的,如果为空下一个节点就是最后一个节点,就将数据存入下一个节点。
然后对比链表节点数if (binCount >= TREEIFY_THRESHOLD - 1)如果达到8了就转换成红黑树,但是转换为红黑树还有一个条件,往下拉查看treeifyBin()方法的源码图,就会发现如果数组容量达不到64的化它会进行扩容而不是转换成红黑树MIN_TREEIFY_CAPACITY=64。
最后就是将旧值替换成新值
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
treeifyBin()方法源码图
其他方法
remove() 删除
size() 数据数量
get() 根据key获取值
LinkedHashMap
LinkedHasMap他的底层实现差不多用的就是它的父类HashMap的,很多方法都重写了父类的,但是put()方法没有重写,而是直接沿用父类方法,其主要的特点就是维护了一个以父类Node组成的Entry双向链表,他会保持存入的顺序。
TreeMap
treemap是由红黑树组成的,其创建的时候会初始化一个比较器,存储也是以键值对的方式
简单的了解就是:
必须实现Compareable接口;
存储的数据是无序的,但提供排序功能(Comparable接口);
存储的元素不再是唯一,具体结果根据Compare方法来决定;
------------------------深入了解TreeMap-----------------------------