HashMap分析
HashMap底层结构是 数组+链表+红黑树,线程不是安全的,key-value都允许为空
性能高,元素顺序结构是无序的并且key不允许重复。
HashMap:适用于Map中插入、删除和定位元素。
put方法详解
package com.studycollectionormap;
import java.util.HashMap;
/**
* put方法详解
* @author admin
* @version 1.0
* HashMap
*/
@SuppressWarnings({"all"})
public class HashMapOrConcurrentHashMap {
public static void main(String[] args){
/**
* 1. 创建HashMap对象
* 创建无参构造器 初始化加载因子loadFactor 为 0.75
* public HashMap() {
* this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
* }
*/
HashMap map = new HashMap();
map.put("aa", 12);
map.put("bb", "dd");
map.put("aa", "cc");
System.out.println("map" + map);
/**
* put方法解读(个人理解)
* 2. public V put(K key, V value) {
* 传入key 和 value,计算hash值 (return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);)
* 然后调用putVal方法
* return putVal(hash(key), key, value, false, true);
* }
*
* 3.执行put方法
* putVal方法解读(个人理解)
* 传入hashi值,key,value
* 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)
* //如果底层table为空 或者 length 为0 ,则扩容 16(相当于第一次添加数据)
* n = (tab = resize()).length;
* //根据hash值计算出table索引位置的Node节点,如果为空,就直接把加入的 k-v,创建成一个Node,加入该位置
* //理解为算出索引位置 如果没有就直接加入
* if ((p = tab[i = (n - 1) & hash]) == null)
* tab[i] = newNode(hash, key, value, null);
* else {
* //第二次添加走这里
* Node<K,V> e; K k;//创建辅助变量
* //p.hash为已有数据的hash值,p.key为已有数据的key
* //如果已有数据的key的hash值与新传入key的hash值相同
* //且满足已有数据的key与新加入的key是同一个对象,并且他们的 equals返回为真
* //则表示不能添加新的key
* if (p.hash == hash &&
* ((k = p.key) == key || (key != null && key.equals(k))))
* e = p;
* //如果当前table中已有node是一个红黑树就按照红黑树规则添加
* else if (p instanceof TreeNode)
* e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
* else {
* //这个else里面写的是 你已经算出了你要存放在某个位置了,但是这个位置是一个链表结构
* //就会对已有链表的每个元素进行一个循环对比
* for (int binCount = 0; ; ++binCount) { //死循环
* //如果已有数据的next为空,则创建 Node节点放入这个位置(理解:为最后一个)
* if ((e = p.next) == null) {
* p.next = newNode(hash, key, value, null);
* //如果这个p.next刚好为8的最后一个则满足下面条件调用treeifyBin方法
* //如果链表个数是否大于等于8
* //如果满足上面条件则调用 treeifyBin(tab, hash);方法
* if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
* treeifyBin(tab, hash);
* break;
* }
* //如果p.next 不为空,则判断key和hash值是否相同,如有相同直接break 放弃添加
* if (e.hash == hash &&
* ((k = e.key) == key || (key != null && key.equals(k))))
* break;
* p = e;
* }
* }
* //e不等于空,说明找到了相同的key,相同key进行 value值替换
* if (e != null) { // existing mapping for key
* V oldValue = e.value;
* if (!onlyIfAbsent || oldValue == null)
* //value值替换
* e.value = value;
* afterNodeAccess(e);
* return oldValue;
* }
* }
* //操作次数加一
* ++modCount;
* //每新增一个node,就size++
* if (++size > threshold)
* //如果长度大于临界值 (0.75*16) 则扩容
* resize();
* afterNodeInsertion(evict);
* //输出为空表示成功
* return null;
* }
*
* //何时转为红黑树(如果链表长度大于8个并且table的大小大于64就会进行树化)
* //如果table为空或者长度小于MIN_TREEIFY_CAPACITY(64),暂时不会树化而是扩容
* final void treeifyBin(Node<K,V>[] tab, int hash) {
* int n, index; Node<K,V> e;
* if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
* resize();
* }
*
*/
}
}