Java集合框架详解(四)Map接口、HashMap类、LinkedHashMap类

news2025/7/21 0:06:44

一、Map接口

  1. Map接口的特点:

(1)映射键值对的形式(key和value);
(2)Map集合中,key是不能重复的,value是可以重复的;
(3)Map集合是散列存放数据的,所以存储顺序与遍历顺序是无序的,即遍历顺序可能与存储顺序不一致。

  1. Map集合的获取方法:
方法名称说明
V get(Object key)根据key获取值
Set keySet()获取所有健的集合
Collection values()获取所有值的集合
Set<Map.Entry<K,V> entrySet()获取所有健值对象的集合
default V getOrDefult(Object key, V defaultValue)如果存在相应的key则返回其对应的value,否则返回给定的默认值defaultValue
eg:
public static void main(String[] args) {
        Map<String, String> hashMap = new HashMap<>();
        hashMap.put("qize01", "小丽");
        hashMap.put("qize02", "天天");
        hashMap.put("qize03", "阿奇");
        hashMap.put("qize04", "毛毛");
        //1、根据键获取值
        System.out.println(hashMap.get("qize01"));
        System.out.println(hashMap.get("ss"));
        //2、获取所有健的集合
        Set<String> stringSet = hashMap.keySet();
        for (String key:stringSet){
            System.out.println(key);
        }
        //3、获取所有value的集合
        Collection<String> values = hashMap.values();
        for (String value:values){
            System.out.println(value);
        }
        //4、获取所有键值对象的集合
        Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
        for (Map.Entry<String, String> entry:entrySet){
            System.out.println(entry);
        }
        //5、如果存在相应的key,则返回其对应的value,否则返回给定的默认值defaultValue
        String qize01 = hashMap.getOrDefault("qize0001","默认值");
        System.out.println(qize01);
 }

二、HashMap类

1、HashMap类特点:
(1)HashMap类实现Map接口;
(2)HashMap类是散列存放数据的,所以存储顺序与遍历顺序是无序的,即遍历顺序可能与存储顺序不一致。
(3)HashMap:底层是基于数组+链表结构来实现的(JDK1.7);基于数组+链表+红黑树实现的(JDK1.8);是线程不安全的。

eg:

Map<String,String> hashMap = new HashMap<>();
hashMap.put("qize001","天天");
hashMap.put("qize002","小丽");
hashMap.put("qize003","莱德");
hashMap.put("qize004","古薇");
System.out.println(hashMap);

2、HashMap类常用方法

方法名称解释
V put(K key, V value)添加元素
V remove(K key, V value)根据健值删除对应的值
void clear()清除所有健值元素
boolean containsKey(Object key)判断集合中是否包含指定的健
boolean containsValue(Object value)判断集合中是否包含指定的值
boolean isEnpty()判断集合是否为空

eg:

public static void main(String[] args) {
	Map<String, String> hashMap = new HashMap<>();
    //put方法
    hashMap.put("qize001","天天");
    hashMap.put("qize002","阿奇");
    hashMap.put("qize003","小丽");
    System.out.println(hashMap);
    System.out.println("------------------");
    //判断集合中是否包含指定的健
    System.out.println(hashMap.containsKey("qize002"));
    //判断集合中是否包含指定的值
    System.out.println(hashMap.containsValue("小丽"));
    //根据健值删除对应的值
    hashMap.remove("qize002");
    System.out.println(hashMap);
    //判断集合是否为空
    System.out.println(hashMap.isEmpty());
    //清除所有健值元素
    hashMap.clear();
    System.out.println(hashMap);
    //判断集合是否为空
    System.out.println(hashMap.isEmpty());
}

3、HashMap集合的遍历
(1)先取到HashMap集合中所有的键,再通过增强for循环调用get方法获取对应的value值:
eg:

public static void main(String[] args) {
    HashMap<String,String> hashMap = new HashMap<>();
    hashMap.put("qize01","毛毛");
    hashMap.put("qize02","天天");
    hashMap.put("qize03","阿奇");
    Set<String> keySet = hashMap.keySet();
    for (String key:keySet){
        String value = hashMap.get(key);
        System.out.println(key+"-"+value);
    }
}

(2)使用entrySet() 方法获取所有健值对象的集合
eg:

public static void main(String[] args) {
    HashMap<String,String> hashMap = new HashMap<>();
    hashMap.put("qize01","毛毛");
    hashMap.put("qize02","天天");
    hashMap.put("qize03","阿奇");
    Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
    for(Map.Entry<String, String> entry:entrySet){
        System.out.println(entry.getKey()+"-"+entry.getValue());
    }
 }

(3)使用entrySet() 方法和 Iterator 获取所有健值对象的集合
eg:

public static void main(String[] args) {
    HashMap<String,String> hashMap = new HashMap<>();
    hashMap.put("qize01","毛毛");
    hashMap.put("qize02","天天");
    hashMap.put("qize03","阿奇");
    Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
    Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
    while (iterator.hasNext()){
        Map.Entry<String, String> entry = iterator.next();
        System.out.println(entry.getKey()+"-"+entry.getValue());
    }
}

4、HashMap集合的底层原理
(1)HashMap 的 key 是否可以设置为自定义对象?可以。
(2)HashMap 存储数据时有序还是无序的?是无序的。
(3)HashMap 是否可以存放null 值?如果可以的话,存放在数组中哪个位置呢?可以存放null值,存放在数组index为0的位置。
(4)HashMap 集合中键值对是如何封装的?是通过实现Map接口封装的Entry对象来封装的。
eg:

public static void main(String[] args) {
    //HashMap 的 key 是否可以设置为自定义对象?可以。
    Student student = new Student("qize01",32);
    HashMap<Student, String> hashMap1 = new HashMap<>();
    hashMap1.put(student, "qize");
    //HashMap 存储数据时有序还是无序的?是无序的。
    HashMap<String, String> hashMap2 = new HashMap<>();
    for (int i=0;i<20; i++){
        hashMap2.put("qize"+i, "i:"+i);
    }
    hashMap2.forEach((k,v) -> {
        System.out.println(k+","+v);
    });
    //HashMap 是否可以存放null 值?如果可以的话,存放在数组中哪个位置呢?
    //可以存放null值,存放在数组index为0的位置
    HashMap<String, String> hashMap3 = new HashMap<>();
    hashMap3.put(null,"毛毛");
}

(5)key的hash算法原理
hashMap集合 1.7版本 是基于数组+链表实现的
hashMap集合 1.8版本 是基于数组+链表+红黑树实现的
根据key的hashCode 取余entrys.length,得到的余数就是该key存放在我们数组中对应的index位置
eg:

public class QizeHashMap<K, V> {
    private  Entry[] entrys = new Entry[10000];

    class Entry<K, V> {
        K k;//key
        V v;//value

        int hash;//key的hash值

        public Entry(K k, V v) {
            this.k = k;
            this.v = v;
        }
    }
    
    public  void put(K k, V v){
        //根据key的hashCode 取余entrys.length
        //得到的余数就是该key存放在我们数组中对应的index位置
        int index = k.hashCode() % entrys.length;
        entrys[index] = new Entry<>(k, v);
    }

    public V get(K k){
        //如果根据key查询的话,hashCode 取余entrys.length
        int index = k.hashCode() % entrys.length;
        return (V) entrys[index].v;
    }

    public static void main(String[] args) {
        QizeHashMap<Object, Object> hashMap = new QizeHashMap<>();
        hashMap.put("qize", "毛毛");
        System.out.println(hashMap.get("qize"));
    }
}

(6)什么是hash冲突问题?
hashCode相同但是值不同,例如 key=“a” 和key=97 最终计算的存放value的下标index相同,则key=97的存放在数组的键值对(Entry对象)会覆盖掉key="a"存放在数组中的键值对。
eg:

//在(5)key的hash算法原理的例子的基础上修改main方法,如下
public static void main(String[] args) {
    QizeHashMap<Object, Object> hashMap = new QizeHashMap<>();
    hashMap.put("a", "毛毛");
    hashMap.put(97, "小丽");
    System.out.println(hashMap.get("a"));
}

运行得到的打印结果为 “小丽” ,而不是 “毛毛” ,这就是hash冲突问题。
在这里插入图片描述
怎么解决hash冲突问题?
在JDK 1.7中是通过链表来解决的。
先判断该index位置 是否有存放键值对(Entry对象),如果取出结果为null,则表示此index位置没有存放数据,则可以直接存放,如果取出的结果为一个Entry对象,则表示此处有hash冲突,需要进行处理。
故上述“(5)key的hash算法原理的例子”可以优化为如下:

public class QizeHashMap<K, V> {
    private  Entry[] entrys = new Entry[10000];

    class Entry<K, V> {
        K k;//key
        V v;//value

        int hash;//key的hash值
        Entry<K, V> next;//Entry的下一个节点

        public Entry(K k, V v, int hash) {
            this.k = k;
            this.v = v;
            this.hash = hash;
        }
    }

    public  void put(K k, V v){
        //根据key的hashCode 取余entrys.length
        //得到的余数就是该key存放在我们数组中对应的index位置

        /**
         * 1、先判断该index位置 是否有存放数据
         * 2、如果取出结果为null,则表示此index位置没有存放数据,则可以直接存放
         * 3、如果取出的结果为一个Entry对象,则表示此处有hash冲突,需要进行处理
         */
        int hash = k.hashCode();
        int index = hash % entrys.length;
        Entry oldEntry = entrys[index];
        if(oldEntry == null){
            entrys[index] = new Entry<>(k, v, hash);
        }else {
            oldEntry.next = new Entry<>(k, v, hash);
        }

    }

    public V get(K k){
        //如果根据key查询的话,hashCode 取余entrys.length
        int hash = k.hashCode();
        int index = hash % entrys.length;
        for (Entry<K, V> entry = entrys[index]; entry != null; entry = entry.next){
            if(entry.hash == hash && (entry.k == k || entry.k.equals(k))){
                return entry.v;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        QizeHashMap<Object, Object> hashMap = new QizeHashMap<>();
        hashMap.put("a", "毛毛");
        hashMap.put(97, "小丽");
        System.out.println(hashMap.get("a"));
    }
}

三、hashCode方法与equals方法

  1. 如果两个对象equals相等,那么这两个对象的HashCode一定也相同;
  2. 如果两个对象的hashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置;
  3. 如果对象的equals方法被重写,那么对象的hashCode方法也尽量重写;
  4. String的equals方法验证的是两个字符串的值是否一样。

eg:

public class Student {
    String name;
    int age;

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

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

    @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(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public static void main(String[] args) {
    /**
     *  equals 属于 object父类中,默认的情况下 在比较两个对象的内存地址是否相同
     *  两个字符串equals 是比较两个对象的值是否相等,因为String类重写了equals方法
     */
    String str1 = "qize";
    String str2 = "qize";
    System.out.println(str1.equals(str2));
    System.out.println("--------------------");
    Student student1 = new Student("qize",22);
    Student student2 = new Student("qize",22);
    System.out.println(student1.equals(student2));
    System.out.println(student1.hashCode());
    System.out.println(student2.hashCode());
}

四、LinkedHashMap集合

LinkedHashMap 继承自HashMap,它的多种操作都是建立在HashMap操作的基础上的,与HashMap不同的是,LinkedHashMap 维护了一个Entry 的双向链表,保证了插入的Entry 中的顺序。
eg:

public static void main(String[] args) {
    LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
    for(int i=1; i<=100; i++){
        linkedHashMap.put("k:"+i,"v:"+i);
    }
    for (Map.Entry<String, String> entry:linkedHashMap.entrySet()){
        System.out.println(entry.getKey()+","+entry.getValue());
    }
}

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

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

相关文章

电脑视频压缩软件哪个好?分享:一款支持上千种视频格式压缩神器

为了追求高清画质&#xff0c;现在的视频文件越来越大了。超大的文件虽然可以给人们带来更好的视觉效果&#xff0c;也给传输和发送带来了很大的麻烦。那有没有一款电脑视频压缩软件解决视频无损压缩问题呢&#xff1f;答案是肯定的&#xff01; 当前&#xff0c; 视频压缩已经…

自动控制系统实验总结

目录 自动控制系统实验总结 稳定性 稳态精准 动态过程 自动控制系统实验总结 自动控制系统是否能很好地工作,是否能精确地保持被控量按照预定的要求规律变化这取决于被控对象和控制器及各功能元器件的特性参数是否设计得当。 在理想情况下,控制系统的输出量…

DM-微皮恩

DM_VPN 动态多站点&#xff0c;Hub-spoken 总分站点的VPN架构&#xff0c;常用于总分之间的结构。 一、DMVPN的四个组件 1. MGRE 2. NHRP(下一跳地址解析协议) 3. Dynamic Routing Protocl 4. IPsec VPN 二、MGRE 1.配置(多点GRE隧道) interface tunnel 0 #进入隧道接口…

FPGA时序约束(一)基本概念入门及简单语法

文章目录一、建立时间和保持时间是什么&#xff1f;二、时序分析分类三、时钟约束方法3.1 时钟约束3.2 输入延时约束3.3输出延时约束3.4时序例外四、时序约束语法补充文章目前大部分参考明德扬时序约束&#xff0c;只是一个学习总结&#xff0c;侵权删 原文链接&#xff1a;FPG…

【跨境电商】如何创建吸引人的免费送货电子邮件营销

关键词&#xff1a;跨境电商、电子邮件营销、免费送货 除了用于接触新受众的新策略外&#xff0c;电子邮件营销仍然是推动更多电子商务网站转化的最有效选择之一。在大多数情况下&#xff0c;电子邮件用于推销新产品&#xff0c;通知客户有关销售、交易和季节性活动的信息&…

域名服务:域名迁移

摘要&#xff1a;这里记录一下西部数据域名的迁移步骤&#xff0c;迁移的域名为从西部数据一个账号迁移至另一个西数数据账号。域名的实体认证为同一主体&#xff0c;迁移后无需重新备案。此处为一家公立医院。 相关文章 域名服务&#xff1a;西部数据域名迁移阿里云Symantec免…

leetcode337打家劫舍3刷题打卡

337. 打家劫舍 III - 力扣&#xff08;Leetcode&#xff09; 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为 root 。 除了 root 之外&#xff0c;每栋房子有且只有一个“父“房子与之相连。一番侦察之后&#xff0c;聪明的小偷意识到“这个…

索引生命周期管理ILM看完不懂你找我

阅读完本文你可以学到什么是索引生命周期管理&#xff0c;各个阶段可以做的操作以及如何使用索引模版使用索引生命周期策略&#xff0c;下面就跟我一起来吧 基础理论篇 索引生命周期管理&#xff08;ILM&#xff09;是一种可以让我们随着时间推移自动化的管理索引的一种方式。我…

常见APP攻击方法 以及防御方法介绍(移动安全)

一、常见APP攻击风险以及防御方法介绍 二、APP攻击以及防御方法 案例讲解 1、基于组件攻击 - 应用劫持 用户打开安卓手机上的某一应用&#xff0c;这时&#xff0c;恶意软件侦测到用户的这一动作&#xff0c;如果立即弹出一个与该应用类似的界面&#xff0c;拦截了合法的应用…

logcat日志文件分析

3:显示时间戳日志 adb logcat -v time > d:\文件\log.txt 日志文件分析 输出的日志格式由5部分组成 1:写下日志的时间 2:优先级&#xff0c;日志优先级从低到高分以下几种 v -verbose 最低级别&#xff0c;开发调试中的一些详细信息&#xff0c;仅在开发中使用&#…

动静分离LNMP

目录 安装LNMP 搭建wordpress 搭建WeCenter 根据需求实现动静分离&#xff0c;当客户端访问nginx网站服务时&#xff0c;静态网页nginx本机反馈&#xff0c;动态网页访问PHP&#xff0c;所以需要在nginx服务器中部署论坛后需要拷贝到PHP服务器中。但是如果有NFS或GFS服务器时可…

【数据结构】堆的实现(简单易懂,超级详细!!!)

目录 1、堆的概念及结构 概念 规律 2、堆的实现 2.1结构设计 2.2接口实现 2.3 初始化 2.4堆的向下调整算法 主要思想 涉及问题 代码实现 2.5建堆 思想 代码实现 建堆的时间复杂度 2.6 堆的向上调整算法 主要思想 ​涉及问题 代码实现 2.7 插入 2.8删除…

【HDU No. 2586】 树上距离 How far away ?

【HDU No. 2586】 树上距离 How far away &#xff1f; 杭电 OJ 题目地址 【题意】 有n 栋房屋&#xff0c;由一些双向道路连接起来。 每两栋房屋之间都有一条独特的简单道路&#xff08;“简单”意味着不可以通过两条道路去一个地方&#xff09;。人们每天总是喜欢这样问&a…

CUDA——向量化内存

许多 CUDA 内核受带宽限制&#xff0c;新硬件中触发器与带宽的比率增加导致更多带宽受限内核。 这使得采取措施缓解代码中的带宽瓶颈变得非常重要。 在本文中&#xff0c;我将向您展示如何在 CUDA C/C 中使用矢量加载和存储来帮助提高带宽利用率&#xff0c;同时减少执行指令的…

【附源码】计算机毕业设计JAVA疫情社区志愿者组织的资源管理平台

【附源码】计算机毕业设计JAVA疫情社区志愿者组织的资源管理平台 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#…

Rust权威指南配套手把手笔记

Rust权威指南配套手把手笔记 持续更新ing 共20章&#xff0c;110小节 P1 1.1 - 简介 06:46 P2 1.2 - 安装 Rust 03:18 P3 1.3 - Hello World 04:11 P4 1.4 - Hello Cargo 07:49 P5 2.1 - 猜数游戏&#xff1a;一次猜测 11:47 P6 2.2 - 猜数游戏&#xff1a;生成神秘数字 …

【强化学习论文合集】ICLR-2021 强化学习论文

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

Grad-CAM

其实还是关于yolo的 利用Grad-CAM解释目标检测框架 研究者研究了视觉物体检测器的可解释性问题。具体来说&#xff0c;研究者在YOLO目标检测器的示例中演示了如何将Grad-CAM集成到模型架构中并分析结果。最后展示了如何计算个体检测的基于归因的解释&#xff0c;并发现结果的归…

Biotin-PEG2-alkyne|紫外线可裂解生物素-二聚乙二醇-炔烃|提供光谱图

试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a; 紫外线可切割生物素-PEG2-炔烃含有紫外线可切割碎片(containsa UV cleavable Fragemnt)&#xff0c;试剂通过点击化学与含叠氮化物的分子反应。点击化学生物素标记试剂包含各种点…

深入浅出PyTorch——PyTorch可视化

1. 可视化网络结构 在复杂的网络结构中确定每一层的输入结构&#xff0c;方便我们在短时间内完成debug 1.1 使用print函数打印模型基础信息 使用ResNet18的结构进行展示 import torchvision.models as models model models.resnet18() print(model)#打印结果 ResNet((conv1)…