资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

HasmMap源码自己分析

Java 更新时间: 发布时间: 计算机考试归档 最新发布

HasmMap源码自己分析

HashMap hashmap = new HashMap<>();//初始化加载因子 DEFAULT_LOAD_FACTOR=0.75public HashMap() {    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}hashmap.put("name","wj");public V put(K key, V value) {    return putVal(hash(key), key, value, false, true);}
//计算hash值static final int hash(Object key) {    int h;    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {    Node[] tab;//Node节点数组    Node p; //单个Node节点,Node是一个单项链表    int n, i;    //transient Node[] table,起始为null    if ((tab = table) == null || (n = tab.length) == 0) {          //初始化Node数组,n = 16          n = (tab = resize()).length;    }    //根据i = (n - 1) & hash计算出索引值,n为table.length    if ((p = tab[i = (n - 1) & hash]) == null) {          //如果该Node数组在该索引值没有值,则直接添加          tab[i] = newNode(hash, key, value, null);    } else {        //如果该Node数组在该索引值已存在值        Node e;         K k;        //p是Node数组在该索引的节点        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) {            //如果新值与旧值的key的hash值相同,并且key的地址相同或者key进行equals比较相等,就更新value值                    e = p;        } else if (p instanceof TreeNode) {              e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);        } else {            //发生了hash冲突,循环遍历该Node链表            for (int binCount = 0; ; ++binCount) {                if ((e = p.next) == null) {                    //遍历到链表最后了,直接挂载上去                    p.next = newNode(hash, key, value, null);                    //TREEIFY_THRESHOLD == 8,如果该Node链表的长度超过8了,准备红黑树化                    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)))) {                    //遍历过程中发现有key的hash值相等,并且key的地址相同或者equals相等,直接更新value值,结束遍历                     break;                }                     p = e;            }        }        if (e != null) {            //oldValue原索引Node节点的value值            V oldValue = e.value;            //onlyIfAbsent 为 false            if (!onlyIfAbsent || oldValue == null) {                  //将节点Node的value更新为最新的值                  e.value = value;            }                afterNodeAccess(e);            //返回旧的值            return oldValue;        }    }    ++modCount;    //threshold为table.length * 0.75    if (++size > threshold) {        //执行扩容        resize();	}    afterNodeInsertion(evict);    return null;}
//Node是HashMap里的一个内部类,实现了Entry接口,Entry接口是Map接口的内部接口,Node是一个单向链表static class Node implements Map.Entry {    final int hash;    final K key;    V value;    Node next;    Node(int hash, K key, V value, Node next) {        this.hash = hash;        this.key = key;        this.value = value;        this.next = next;    }}
//Node数组扩容机制final Node[] resize() {    //transient Node[] table,起始为null    Node[] oldTab = table;    int oldCap = (oldTab == null) ? 0 : oldTab.length;    int oldThr = threshold;    int newCap, newThr = 0;    if (oldCap > 0) {        if (oldCap >= MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;            return oldTab;        }        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&                 oldCap >= DEFAULT_INITIAL_CAPACITY)            newThr = oldThr << 1; // double threshold    }    else if (oldThr > 0) // initial capacity was placed in threshold        newCap = oldThr;    else {        //第一次put时,oldCap == 0,DEFAULT_INITIAL_CAPACITY = 16        //newCap == 16,newThr == 0.75 * 16 == 12        newCap = DEFAULT_INITIAL_CAPACITY;        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);    }    if (newThr == 0) {        float ft = (float)newCap * loadFactor;        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?                  (int)ft : Integer.MAX_VALUE);    }    threshold = newThr;    @SuppressWarnings({"rawtypes","unchecked"})    //newCap初始化为16    Node[] newTab = (Node[])new Node[newCap];    table = newTab;    if (oldTab != null) {        for (int j = 0; j < oldCap; ++j) {            Node e;            if ((e = oldTab[j]) != null) {                oldTab[j] = null;                if (e.next == null)                    newTab[e.hash & (newCap - 1)] = e;                else if (e instanceof TreeNode)                    ((TreeNode)e).split(this, newTab, j, oldCap);                else { // preserve order                    Node loHead = null, loTail = null;                    Node hiHead = null, hiTail = null;                    Node next;                    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;                    }                }            }        }    }    return newTab;}

总结:

  1. 加载因子0.75是在创建HashMap实例的时候确定的
  2. Node table[] 是在第一次put时才会初始化大小,起始为16,每次进行put操作时size会+1,发生hash冲突进行的链表操作不会加一,当size超过 table.length * 加载因子 就会触发扩容,进行数组拷贝,长度变为原数组的两倍,并且会重新计算索引值,也就是说原索引为6的Node节点扩容后索引值并不一定还是6
  3. 对于key的hash值相同,并且满足key的地址相同或者equals相同,会将旧的value值更新,并返回旧的value值
  4. 发生hash冲突时,采用遍历Node链表进行插入,遍历过程中有满足3的会执行3的操作,没有则插到链表尾
  5. 在链表长度超过8时,会进行是否树化的判断,只有当Node数组的长度大于64才会进行红黑树化,否则会直接触发扩容
转载请注明:文章转载自 http://www.konglu.com/
本文地址:http://www.konglu.com/it/1095260.html
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【HasmMap源码自己分析】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2