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

news2024/9/21 4:40:47

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.coloradmin.cn/o/932255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多语言对接电商平台api接口获取京东商品评论数据代码展示示例

商品评论接口的意义&#xff1a; 确认消费者关注与产品卖点是否一致&#xff1b; 洞察用户对价格、促销、直播的敏感度&#xff1b;发现产品质量、客服、物流等方面的问题&#xff1b;找到品牌宣称与用户预期、实际场景之间差异化&#xff1b;挖掘消费者偏好的差异性&#xff…

【设计模式--原型模式(Prototype Pattern)

一、什么是原型模式 原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;它的主要目的是通过复制现有对象来创建新的对象&#xff0c;而无需显式地使用构造函数或工厂方法。这种模式允许我们创建一个可定制的原型对象&#xff0c;然后通过复制…

windows下Qt、MinGW、libmodbus源码方式的移植与使用

windows下Qt、MinGW、libmodbus源码方式的移植与使用 1、前言 libmodbus官网&#xff1a;https://libmodbus.org/ github下载&#xff1a;https://github.com/stephane/libmodbus 截止2023年8月26日时&#xff0c;libmodbus最新版本为3.1.10&#xff0c;本篇博客基于此版本进…

揭秘蓝牙技术:从概念到应用的全解析

目录 引言一、蓝牙技术的概念和历史1、简介2、各个版本3、分类 二、蓝牙技术的工作原理二、蓝牙技术的优点和缺点三 、蓝牙技术的设计和应用四、总结 引言 当我们谈论蓝牙技术时&#xff0c;首先浮现在脑海中的可能是那些小巧的、形似鹅卵石的设备。它们是我们的移动电话、平板…

MIUI 欧版刷机教程(操作篇)

文章目录 0 前置条件1 下载ROM包2 确定刷机方式3 线刷教程4 卡刷教程使用系统更新使用 TWRP 问题汇总 0 前置条件 必须先解除手机的 bootloader 锁。详细教程参见官网&#xff1a;申请解锁小米手机 (miui.com)。 1 下载ROM包 在 MIUI EU 官方论坛&#xff08;需要科学上网&a…

java八股文面试[多线程]——合适的线程数是多少

知识来源&#xff1a; 【并发与线程】 合适的线程数量是多少&#xff1f;CPU 核心数和线程数的关系&#xff1f;_哔哩哔哩_bilibili

深入篇【C++】set和map(multiset/multimap)特性总结与使用

深入篇【C】set和map(multiset/multimap&#xff09;特性总结与使用 一.set/multiset总结二.map/multiset总结三.set/map应用 一.set/multiset总结 set是按照一定次序存储元素的容器在set中&#xff0c;元素的value也标识它(value就是key&#xff0c;类型为T)&#xff0c;并且每…

【趣味随笔】怎么维护自己的电脑?

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

微信小程序开发教学系列(4)- 数据绑定与事件处理

4. 数据绑定与事件处理 在微信小程序中&#xff0c;数据绑定和事件处理是非常重要的部分。数据绑定可以将数据和页面元素进行关联&#xff0c;实现数据的动态渲染&#xff1b;事件处理则是响应用户的操作&#xff0c;实现交互功能。本章节将详细介绍数据绑定和事件处理的基本原…

Java项目-苍穹外卖-Day06-微信小程序开发

文章目录 前言1.HttpClienthttpclient是什么入门案例发送GET请求发送POST请求Httpclient工具类 2.微信小程序介绍准备工作注册小程序和完善对应信息下载开发者工具 入门案例 前言 本篇主要是主要是wx小程序开发入门和HttpClient的使用介绍 完成了苍穹外卖用户端的 微信登陆 和…

Leetcode-每日一题【剑指 Offer 37. 序列化二叉树】

题目 请实现两个函数&#xff0c;分别用来序列化和反序列化二叉树。 你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑&#xff0c;你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。 …

抖店必须绑定抖音账号吗?聊6个抖店不为人知的小细节,别外传

我是王路飞。 现在做抖店&#xff0c;比如绑定一个抖音账号吗&#xff1f; 了解过抖店的朋友都知道&#xff0c;之前开通抖音小店&#xff0c;是需要绑定一个抖音号作为店铺的官方账号的。 而且属于硬性规定&#xff0c;必须要绑定&#xff0c;否则店铺无法正常运营。 但是…

Adams软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Adams是一款由Mechanical Dynamics Inc&#xff08;MDI&#xff09;开发的有限元分析软件&#xff0c;主要用于模拟机械系统的运动和动力学行为。它广泛应用于汽车、航空航天、机械、电子等多个领域。以下是对Adams软件的详细介…

利用lammps模拟蓝宝石在水润滑环境下的抛光

一 问题描述 蓝宝石&#xff08;Al2O3&#xff09;由于其独特的晶体结构&#xff0c;优异的物理化学特性&#xff0c;被广泛应用于航空航天等领域。高精尖的应用领域要求蓝宝石具有纳米级的表面粗糙度以及严格可控的亚表面缺陷。影响超精密加工最终性能的因素主要集中在工件表…

Linux学习之Ubuntu 20使用systemd管理OpenResty服务

sudo cat /etc/issue可以看到操作系统的版本是Ubuntu 20.04.4 LTS&#xff0c;sudo lsb_release -r可以看到版本是20.04&#xff0c;sudo uname -r可以看到内核版本是5.5.19&#xff0c;sudo make -v可以看到版本是GNU Make 4.2.1。 需要先参考我的博客《Linux学习之Ubuntu 2…

Ngnix配置Minio动态代理:访问桶列表报错解决方案:

报错信息&#xff1a; Objects List unavailable. Please review your WebSockets configuration and try again nginx配置如下: [rootwww conf]# cat nginx.conf #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #erro…

朋友圈如何快速转发?怎么自动定时转发朋友圈?

微信朋友圈是微信的一个功能&#xff0c;可以让用户分享生活动态、照片、视频等&#xff0c;也可以看到好友分享的动态。朋友圈的分享可以增加社交互动&#xff0c;可以加强朋友之间的联系&#xff0c;分享彼此的生活和心情。 转发朋友圈的作用也是非常明显的。当用户看到有趣的…

ChatGPT安全吗?一文解析聊天机器人数据隐私和安全问题

ChatGPT大体上很安全&#xff0c;但你仍应谨慎对待。 无论是起草论文还是研究工作中的问题&#xff0c;ChatGPT已经成为处理任何文字任务的上佳工具。 的确&#xff0c;聊天机器人快速处理大量数据的能力使其极具价值&#xff0c;但是&#xff0c;这种便利是否意味着要付出代…

Zebec在Nautilus Chain 开启质押,ZBC 将极致通缩

前不久&#xff0c;Zebec Protocol 旗下的模块化公链 Nautilus Chain 上线了主网&#xff0c;模块化 Layer3 体系正式开启。在 Nautilus Chain 主网上线的初期阶段&#xff0c;将以 ZBC 通证作为链上主要的职能通证&#xff0c;用于 Gas 消耗、治理等诸多方面。据悉&#xff0c…