Java基础知识总结(17)

存放机制

1.初始化表格

默认情况构建HashMap时,如果表格table为Null,那么首先先new 一个table数组出来,里面存储的都是node

2.基于映射找到节点

存放时基于 key 和 value的键值对

首先基于key进行哈希函数的计算 将结果与table容量-1进行与运算 得到在table数组中的索引位置

3.添加或者更新节点

table数组中对应的位置有三种情况

对应位置为空---> 直接new Node() 把key ,value,哈希值,next全部封装到Node里面,然后把Node对象放到数组对应位置。

对应位置已经存放了Node对象,那么就遍历链表,如果在遍历过程中找到了hasCode和key值与添加节点相同,那么直接替换,如果没有找到相同的节点,那么直接将新节点添加到链表的末尾。在添加过程中,链表长度如果大于树化的阈值,树化的阈值默认为8,table的容量默认大于64时才能树化。容量没有达到64,要先扩容到64 然后再树化

对应位置是TreeNode ,那么就会基于红黑树的操作,将节点添加到红黑树里面,如果说红黑树里面已经key值相同的节点,就执行替换操作。

复制代码
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
​
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        // i为数组下标  p为数组项中存放的链表
        HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;
        //判断table是否为空,table对象是node数组,即hashmap中数据+链表+红黑树中的数组
        if ((tab = table) == null || (n = tab.length) == 0)
            //对hashmap的临界值和数组进行初始化
            n = (tab = resize()).length;
        //计算当前对象存放的下标,并判断数组中该下标是否已经存值
        if ((p = tab[i = (n - 1) & hash]) == null)
            ///如果不存在则在该位置创建一个新的链表。并将目标值存入新链表的表头
            tab[i] = newNode(hash, key, value, null);
        else {
            HashMap.Node<K,V> e; K k;
            //判断目标key的hash值与链表头节点的hash值是否相等,它们的key是否相等
            if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            //判断p节点的类型是否是TreeNode
            else if (p instanceof HashMap.TreeNode)
                //如果红黑树节点中不存在与目标key相同的值,将目标对象插入红黑树中,存在相同的key则返回已存在的对象
                e = ((HashMap.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);
                        //判断链表长度是否大于8
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            //将链表转化为红黑树
                            treeifyBin(tab, hash);
                        break;
                    }
                    //遍历的过程中发现链表中有key与目标对象的key相同
                    if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            //如果e不为空说明,hashmap中已经存在了当前目标对象的key,则将value进行覆盖
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                //修改值后,返回旧值
                return oldValue;
            }
        }
        //记录HashMap结构被修改的次数
        ++modCount;
        //判断数组大小是否已经大于临界值了
        if (++size > threshold)
            //进行扩容
            resize();
        afterNodeInsertion(evict);
        //Hashmap中不存在key,所以返回null
        return null;
    }
​
​
    final void treeifyBin(HashMap.Node<K,V>[] tab, int hash) {
        int n, index; HashMap.Node<K,V> e;
        //如果数组大小小于64
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            //进行扩容
            resize();
        //链表结构转红黑树
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            HashMap.TreeNode<K,V> hd = null, tl = null;
            do {
                HashMap.TreeNode<K,V> p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }

4.超过阈值进行扩容

先添加再决定要不要扩容

整体表格的总元素数量超出阈值,对table进行扩容

扩容机制

扩容需要解决的问题?

1.计算新表格的大小,在原基础之上乘以2

2.遍历表、链、树中的元素,重新映射并拷贝至新位置

相关推荐
奶香臭豆腐6 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
晚夜微雨问海棠呀13 分钟前
长沙景区数据分析项目实现
开发语言·python·信息可视化
graceyun14 分钟前
C语言初阶习题【9】数9的个数
c语言·开发语言
hanbarger16 分钟前
mybatis框架——缓存,分页
java·spring·mybatis
cdut_suye23 分钟前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
苹果醋335 分钟前
2020重新出发,MySql基础,MySql表数据操作
java·运维·spring boot·mysql·nginx
小蜗牛慢慢爬行37 分钟前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
azhou的代码园40 分钟前
基于JAVA+SpringBoot+Vue的制造装备物联及生产管理ERP系统
java·spring boot·制造
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Swift社区1 小时前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift