Java中HashMap的基本介绍和详细讲解,HashMap的遍历以及HashMap的底层源码的分析

HashMap 基本介绍

HashMap 是 Java 中的一个集合类,实现了 Map 接口用于存储键值对(key-value)数据。它基于哈希表的数据结构实现,可以实现高效的查找、插入和删除操作。

HashMap 细节讨论

  1. 无序性: HashMap 中的元素是无序的,即遍历的顺序不一定是元素插入的顺序。
  2. 键唯一性: HashMap键是唯一的,不允许重复的键。如果插入相同的键,后面的值会覆盖前面的值
  3. 允许 null 键和 null 值: HashMap 允许使用 null 作为键并且允许键对应的值为 null,但是只允许有一个null键,因为键是唯一的。
  4. 非线程安全: HashMap 不是线程安全的,如果多个线程同时访问并修改同一个 HashMap,可能会导致数据不一致或其他错误。
  5. 初始容量和负载因子: HashMap 允许设置初始容量和负载因子,初始容量是哈希表中桶的数量,负载因子是哈希表在达到多满时进行扩容操作(这里和HashSet一样,因为HashSet的底层是用HashMap实现的)。

使用注意事项

  1. 线程安全性: 如果需要在多线程环境中使用 HashMap,需要进行适当的同步处理,或者考虑使用线程安全的集合类(如 ConcurrentHashMap)。
  2. 哈希冲突: 当不同的键映射到相同的哈希值时,发生哈希冲突。HashMap 使用链表(JDK8 之前)或红黑树(JDK8 及以后)来处理哈希冲突。
  3. equals 和 hashCode 方法: 在使用自定义类作为 HashMap 的键时,需要正确实现该类的 equalshashCode 方法,以确保键的唯一性和正确的哈希计算。

常用方法

以下是一些常用的 HashMap 方法:

  • put(key, value): 向 HashMap 中插入键值对。
  • get(key): 根据键获取对应的值。
  • containsKey(key): 判断是否包含指定键。
  • containsValue(value): 判断是否包含指定值。
  • remove(key): 根据键删除对应的键值对。
  • size(): 返回 HashMap 中键值对的数量。
  • isEmpty(): 判断 HashMap 是否为空。
  • keySet(): 返回包含所有键的集合。
  • values(): 返回包含所有值的集合。
  • entrySet(): 返回包含所有键值对的集合。

底层源码和底层实现

HashMap 的底层实现主要是基于哈希表,其中每个桶(bucket)是一个链表或红黑树。当哈希冲突发生时,新的键值对会被插入到相应的桶中。

HashMap 的底层源码非常复杂,涉及哈希计算、扩容、桶的处理等多个方面。如果想深入了解 HashMap 的底层实现,可以查阅 Java 的源代码或相关的学习资料。

在这里插入图片描述
HashMap的遍历代码:

public class HashMap_ {
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        hashMap.put(1,new Student("1","ret1",23,"计算机"));
        hashMap.put(2,new Student("2","ret2",23,"计算机"));
        hashMap.put(3,new Student("3","ret3",23,"计算机"));
        System.out.println(hashMap);
        for (Object entry : hashMap.entrySet()) {
            Map.Entry entry1 = (Map.Entry) entry;
            System.out.println(entry1.getKey()+"        "+entry1.getValue());
        }

        Set set = hashMap.keySet();
        for (Object key :set) {
            System.out.println(key+"    "+hashMap.get(key));
        }


    }
}

class Student{
    private String sno;
    private String name;
    private int age;
    private String major;

    public Student(String sno, String name, int age, String major) {
        this.sno = sno;
        this.name = name;
        this.age = age;
        this.major = major;
    }

    public String getSno() {
        return sno;
    }

    public void setSno(String sno) {
        this.sno = sno;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(sno, student.sno) && Objects.equals(name, student.name) && Objects.equals(major, student.major);
    }

    @Override
    public int hashCode() {
        return Objects.hash(sno, name, age, major);
    }

    @Override
    public String toString() {
        return "Student{" +
                "sno='" + sno + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", major='" + major + '\'' +
                '}';
    }
}

HashMap的底层代码:

/*HashMap底层原理
        1. 执行构造器 new HashMap()
        初始化加载因子 loadFactor = 0.75
        HashMap$Node[] table = null
        2. 执行 put 调用 hash 方法,计算 key 的 hash 值(h = key.hashCode()) ^ (h >>> 16)
        public V put (K key, V value){
            //K = "java" value = 10
            return putVal(hash(key), key, value, false, true);
        }
        3. 执行 putVal
        final V putVal ( int hash, K key, V value,boolean onlyIfAbsent, boolean evict){
            Node<K, V>[] tab;
            Node<K, V> p;
            int n, i;//辅助变量
            //如果底层的 table 数组为 null, 或者 length =0 , 就扩容到 16
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            //取出 hash 值对应的 table 的索引位置的 Node, 如果为 null, 就直接把加入的 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;//辅助变量
                // 如果 table 的索引位置的 key 的 hash 相同和新的 key 的 hash 值相同,
                // 并满足(table 现有的结点的 key 和准备添加的 key 是同一个对象 || equals 返回真)就认为不能加入新的 k-v
                if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;
                else if (p instanceof TreeNode)//如果当前的 table 的已有的 Node 是红黑树,就按照红黑树的方式处理
                    e = ((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 个,到 8 个,后
                            //就调用 treeifyBin 方法进行红黑树的转换
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        if (e.hash == hash && //如果在循环比较过程中,发现有相同,就 break,就只是替换 value
                                ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value; //替换,key 对应 value
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            ++modCount;//每增加一个 Node ,就 size++
            if (++size > threshold[12 - 24 - 48])//如 size > 临界值,就扩容
                resize();
            afterNodeInsertion(evict);
            return null;
        }
        5. 关于树化(转成红黑树)
        //如果 table 为 null ,或者大小还没有到 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();
        }
        */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/90740.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python高光谱遥感数据处理与高光谱遥感机器学习方法应用

本文提供一套基于Python编程工具的高光谱数据处理方法和应用案例。 本文涵盖高光谱遥感的基础、方法和实践。基础篇以学员为中心&#xff0c;用通俗易懂的语言解释高光谱的基本概念和理论&#xff0c;旨在帮助学员深入理解科学原理。方法篇结合Python编程工具&#xff0c;专注…

【C++】list

list 1. 简单了解list2. list的常见接口3. 简单实现list4. vector和list比较 1. 简单了解list list的底层是带头双向循环列表。因此list支持任意位置的插入和删除&#xff0c;且效率较高。但其缺陷也很明显&#xff0c;由于各节点在物理空间是不连续的&#xff0c;所以不支持对…

thinkphp安装workman

需要加版本&#xff0c;版本太高了不行 composer require topthink/think-worker1.0.*

Github的使用指南

首次创建仓库 1.官网创建仓库 打开giuhub官网&#xff0c;右上角点击你的头像&#xff0c;随后点击your repositories 点击New开始创建仓库 如下图为创建仓库的选项解释 出现如下界面就可以进行后续的git指令操作了 2.git上传项目 进入需上传项目的所在目录&#xff0c;打开…

keepalived+haproxy 搭建高可用高负载高性能rabbitmq集群

一、环境准备 1. 我这里准备了三台centos7 虚拟机 主机名主机地址软件node-01192.168.157.133rabbitmq、erlang、haproxy、keepalivednode-02192.168.157.134rabbitmq、erlang、haproxy、keepalivednode-03192.168.157.135rabbitmq、erlang 2. 关闭三台机器的防火墙 # 关闭…

自动控制原理笔记-采样控制系统

目录 采样控制系统的基本概念&#xff1a; 采样过程及采样定理&#xff1a; 一、采样过程 二、采样定理&#xff08;香农采样定理、奈奎斯特采样定律&#xff09; 三、信号复现 四、零阶保持器 z变换与z反变换&#xff1a; z变换的定义 z变换基本定理 z反变换 采样系…

gorm中正确的使用json数据类型

一、说明 1、JSON 数据类型是 MySQL 5.7.8 开始支持的。在此之前&#xff0c;只能通过字符类型&#xff08;CHAR&#xff0c;VARCHAR 或 TEXT &#xff09;来保存 JSON 文档。现实中也很多人不会采用json的存储方式&#xff0c;直接定义一个字符类型,让前端转换传递进来,返回给…

HTTPS协议加密原理

目录 一、什么是HTTPS 二、什么是加密/解密 三、为什么要加密 四、常见的加密方式 1.对称加密 2. 非对称加密 五、HTTPS加密方式探讨 1.只使用对称加密 2.只使用非对称加密 3.非对称加密对称加密 4.非对称加密对称加密CA认证 六、总结 一、什么是HTTPS HTTP 协议&a…

vue3+element下拉多选框组件

<!-- 下拉多选 --> <template><div class"select-checked"><el-select v-model"selected" :class"{ all: optionsAll, hidden: selectedOptions.data.length < 2 }" multipleplaceholder"请选择" :popper-app…

git及GitHub的使用

文章目录 git在本地仓库的使用github使用创建仓库https协议连接(不推荐&#xff0c;现在用起来比较麻烦)ssh连接&#xff08;推荐&#xff09;git分支操作冲突处理忽略文件 git在本地仓库的使用 1.在目标目录下右键打开git bash here 2.创建用户名和邮箱(注&#xff1a; 下载完…

ms-tpm-20-ref 在linux下编译

1、代码地址&#xff0c; GitHub - microsoft/ms-tpm-20-ref: Reference implementation of the TCG Trusted Platform Module 2.0 specification.Reference implementation of the TCG Trusted Platform Module 2.0 specification. - GitHub - microsoft/ms-tpm-20-ref: Refe…

Nodejs-nrm:快速切换npm源 / npm官方源和其他自定义源之间切换

一、理解 Nodejs nrm Nodejs nrm 是一个管理 npm 源的工具。由于 npm 在国内的速度较慢&#xff0c;很多开发者会使用淘宝的 npm 镜像源&#xff0c;但是也会遇到一些问题&#xff0c;例如某些包在淘宝镜像源中不存在&#xff0c;或者淘宝镜像源本身也会有问题。 Nodejs nrm …

CSS scoped 属性的原理

scoped 一、scoped 是什么&#xff1f;二、实现原理 一、scoped 是什么&#xff1f; 在 Vue 组件中&#xff0c;为了使样式私有化&#xff08;模块化&#xff09;&#xff0c;不对全局造成污染&#xff0c;可以在 style 标签上添加 scoped 属性以表示它的只属于当下的模块&am…

【MOS管的作用和工作原理】

数电/模电知识学习与分享001 MOS管的作用和工作原理1、MOS管基本概念2、MOS管基本原理3、MOS管广泛作用4、MOS管特点4、参考文献 MOS管的作用和工作原理 1、MOS管基本概念 MOS管&#xff08;Metal-Oxide-Semiconductor Field-Effect Transistor&#xff09;是一种常用的半导体…

Unity 之利用 localEulerAngle与EulerAngle 控制物体旋转

文章目录 概念讲解localEulerAngle与EulerAngle的区别 概念讲解 欧拉角&#xff08;Euler Angles&#xff09;是一种常用于描述物体在三维空间中旋转的方法。它使用三个角度来表示旋转&#xff0c;分别绕物体的三个坐标轴&#xff08;通常是X、Y和Z轴&#xff09;进行旋转。这…

AI Agent在情景猜谜场景下的AgentBench基准测试

目录 AgentBench评估哪些场景? 近日,来自清华大学、俄亥俄州立大学和加州大学伯克利分校的研究者设计了一个测试工具——AgentBench,用于评估LLM在多维度开放式生成环境中的推理能力和决策能力。研究者对25个LLM进行了全面评估,包括基于API的商业模型和开源模型。 他们发现…

安卓移动应用开发实训室建设方案

一 、系统概述 安卓移动应用开发作为新一代信息技术的重点和促进信息消费的核心产业&#xff0c;已成为我国转变信息服务业的发展新热点&#xff1a;成为信息通信领域发展最快、市场潜力最大的业务领域。互联网尤其是移动互联网&#xff0c;以其巨大的信息交换能力和快速渗透能…

es的索引管理

概念 &#xff08;1&#xff09;集群&#xff08;Cluster&#xff09;&#xff1a; ES可以作为一个独立的单个搜索服务器。不过&#xff0c;为了处理大型数据集&#xff0c;实现容错和高可用性&#xff0c;ES可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。 &…

docker项目实战

目录 1、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 1&#xff09;拉取mysql:5.6和owncloud镜像 2&#xff09;后台运行容器 3&#xff09;通过ip:端口的方式访问owncloud 2、安装搭建私有仓库 Harbor 1&#xff09;首先准备所需包 2&#xff09;安装h…

JavaScript——为什么静态方法不能调用非静态方法

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…
最新文章