zoukankan      html  css  js  c++  java
  • HashMap源码分析

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;
        // 1.如果table为空或者长度为0,即没有元素,那么使用resize()方法扩容
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // 2.计算插入存储的数组索引i,此处计算方法同 1.7 中的indexFor()方法
        // 如果数组为空,即不存在Hash冲突,则直接插入数组
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        // 3.插入时,如果发生Hash冲突,则依次往下判断
        else {
            HashMap.Node<K,V> e; K k;
            // a.判断table[i]的元素的key是否与需要插入的key一样,若相同则直接用新的value覆盖掉旧的value
            // 判断原则equals() - 所以需要当key的对象重写该方法
            if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // b.继续判断:需要插入的数据结构是红黑树还是链表
            // 如果是红黑树,则直接在树中插入 or 更新键值对
            else if (p instanceof HashMap.TreeNode)
                e = ((HashMap.TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            // 如果是链表,则在链表中插入 or 更新键值对
            else {
                // i .遍历table[i],判断key是否已存在:采用equals对比当前遍历结点的key与需要插入数据的key
                //    如果存在相同的,则直接覆盖
                // ii.遍历完毕后任务发现上述情况,则直接在链表尾部插入数据
                //    插入完成后判断链表长度是否 > 8:若是,则把链表转换成红黑树
                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;
                }
            }
            // 对于i 情况的后续操作:发现key已存在,直接用新value覆盖旧value&返回旧value
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        // 插入成功后,判断实际存在的键值对数量size > 最大容量
        // 如果大于则进行扩容
        if (++size > threshold)
            resize();
        // 插入成功时会调用的方法(默认实现为空)
        afterNodeInsertion(evict);
        return null;
    }
  • 相关阅读:
    68
    56
    Django manager 命令笔记
    Django 执行 manage 命令方式
    Django 连接 Mysql (8.0.16) 失败
    Python django 安装 mysqlclient 失败
    H.264 SODB RBSP EBSP的区别
    FFmpeg—— Bitstream Filters 作用
    MySQL 远程连接问题 (Windows Server)
    MySQL 笔记
  • 原文地址:https://www.cnblogs.com/echola/p/13695599.html
Copyright © 2011-2022 走看看