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.遍历表、链、树中的元素,重新映射并拷贝至新位置

相关推荐
PythonFun13 分钟前
Python批量下载PPT模块并实现自动解压
开发语言·python·powerpoint
Death20017 分钟前
Qt 6 相比 Qt 5 的主要提升与更新
开发语言·c++·qt·交互·数据可视化
机器视觉知识推荐、就业指导20 分钟前
使用Qt实现实时数据动态绘制的折线图示例
开发语言·qt
快乐就好ya1 小时前
Java多线程
java·开发语言
IT学长编程1 小时前
计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·二手图书交易系统
CS_GaoMing2 小时前
Centos7 JDK 多版本管理与 Maven 构建问题和注意!
java·开发语言·maven·centos7·java多版本
艾伦~耶格尔2 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20172 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端
2401_858120533 小时前
Spring Boot框架下的大学生就业招聘平台
java·开发语言
S hh3 小时前
【Linux】进程地址空间
java·linux·运维·服务器·学习