#Java-集合进阶-Map

1.Map

声明1

1.1 双列集合的特点

请添加图片描述

单列集合一次只能添加一个元素,双列集合一次可以添加一对元素
例:

小米手机2000
华为手机5000
苹果手机9000

这三对元素,左边的我们称之为,右边的称为。他们是一一对应的关系
所以双列集合中的元素又叫键值对、键值对对象、Entry

总结:
双列集合的特点

  1. 双列集合一次需要存一对数据,分别为键和值
  2. 键不能重复, 值可以重复
  3. 键和值是一一对应的,每一个键只能找到自己对应的值
  4. 键+值 这个整体 我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象

1.2Map集合方法

  • 方法介绍

    方法名说明
    V put(K key,V value)添加元素2
    V remove(Object key)根据键删除键值对元素3
    void clear()移除所有的键值对元素
    boolean containsKey(Object key)判断集合是否包含指定的键
    boolean containsValue(Object value)判断集合是否包含指定的值
    boolean isEmpty()判断集合是否为空
    int size()集合的长度,也就是集合中键值对的个数
    • 当键不存在的时候返回的是null
    • 当集合中有键的时候会覆盖这个键对应的值并把这个值进行返回
  • 示例代码

    public class MapDemo02 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String,String> map = new HashMap<String,String>();
    
            //V put(K key,V value):添加元素
            map.put("张无忌","赵敏");
            map.put("郭靖","黄蓉");
            map.put("杨过","小龙女");
    
    		//V remove(Object key):根据键删除键值对元素
          System.out.println(map.remove("郭靖"));
            System.out.println(map.remove("郭襄"));
    
            //void clear():移除所有的键值对元素      
              map.clear();
    
            //boolean containsKey(Object key):判断集合是否包含指定的键
            System.out.println(map.containsKey("郭靖"));
            System.out.println(map.containsKey("郭襄"));
    
            //boolean isEmpty():判断集合是否为空
            System.out.println(map.isEmpty());
    
            //int size():集合的长度,也就是集合中键值对的个数
            System.out.println(map.size());
    
            //输出集合对象
            System.out.println(map);
        }
    }
    

1.3Map集合的获取方法

  • 方法介绍

    方法名说明
    V get(Object key)根据键获取值
    Set keySet()获取所有键的集合
    Collection values()获取所有值的集合
    Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合
  • 示例代码

    public class MapDemo03 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    
            //V get(Object key):根据键获取值
    //        System.out.println(map.get("张无忌"));
    //        System.out.println(map.get("张三丰"));
    
            //Set<K> keySet():获取所有键的集合
    //        Set<String> keySet = map.keySet();
    //        for(String key : keySet) {
    //            System.out.println(key);
    //        }
    
            //Collection<V> values():获取所有值的集合
            Collection<String> values = map.values();
            for(String value : values) {
                System.out.println(value);
            }
        }
    }
    

1.4Map集合的遍历

遍历1

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 把所有的丈夫给集中起来
      • 遍历丈夫的集合,获取到每一个丈夫
      • 根据丈夫去找对应的妻子
  • 步骤分析

    • 获取所有键的集合。用keySet()方法实现
    • 遍历键的集合,获取到每一个键。用增强for实现
    • 根据键去找值。用get(Object key)方法实现
  • 代码实现

    在进行遍历的时候可以使用以前我们使用的三种方法:

    • 迭代器
    • 增强for
    • Lamda表达式
    public class MapDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    
            //获取所有键的集合。用keySet()方法实现
            Set<String> keySet = map.keySet();
            //遍历键的集合,获取到每一个键。用增强for实现
            for (String key : keySet) {
                //根据键去找值。用get(Object key)方法实现
                String value = map.get(key);
                System.out.println(key + "," + value);
            }
        }
    }
    

遍历2

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 获取所有结婚证的集合
      • 遍历结婚证的集合,得到每一个结婚证
      • 根据结婚证获取丈夫和妻子
  • 步骤分析

    • 获取所有键值对对象的集合

      • Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
    • 遍历键值对对象的集合,得到每一个键值对对象

      • 用增强for实现,得到每一个Map.Entry4
    • 根据键值对对象获取键和值

      • getKey()得到键
      • getValue()得到值

      这里的get方法应该是特有的方法,获得键和值

  • 代码实现

    public class MapDemo02 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    
            //获取所有键值对对象的集合
            Set<Map.Entry<String, String>> entrySet = map.entrySet();
            //遍历键值对对象的集合,得到每一个键值对对象
            for (Map.Entry<String, String> me : entrySet) {
                //根据键值对对象获取键和值
                String key = me.getKey();
                String value = me.getValue();
                System.out.println(key + "," + value);
            }
        }
    }
    

forEeach遍历3

使用Map.ForEach()方法传入匿名内部类来遍历

同时使用Lambda表达式来简化代码

Map<String , Integer> map1 = new HashMap<>();
map1.forEach(new BiConsumer<String, Integer>() {
    @Override
    public void accept(String s, Integer integer) {

    }
});

我们要注意:上述的Biconsumer接口的泛型类型和所处的代码环境有关,在主方法中推荐的泛型类型是:<T extends Object, U extends Object>

1.5HashMap集合

HashMap集合概述和特点
  1. 所有Map集合的特点都是由键决定的:
  • 存取无序
  • 不重复
  • 无索引
  1. 特点:

    • HashMap底层是哈希表结构的
    • 依赖hashCode方法和equals方法保证的唯一
    • 如果键要存储的是自定义对象,需要重写hashCode和equals方法

    需要注意只跟键有关,当键的值重复的时候,就会进行覆盖而不是舍弃,这一点和HashSet有所区别

HashMap集合应用
  • 案例需求

    • 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
    • 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
  • 代码实现

    学生类

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            Student student = (Student) o;
    
            if (age != student.age) return false;
            return name != null ? name.equals(student.name) : student.name == null;
        }
    
        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + age;
            return result;
        }
    }
    

    测试类

    public class HashMapDemo {
        public static void main(String[] args) {
            //创建HashMap集合对象
            HashMap<Student, String> hm = new HashMap<Student, String>();
    
            //创建学生对象
            Student s1 = new Student("林青霞", 30);
            Student s2 = new Student("张曼玉", 35);
            Student s3 = new Student("王祖贤", 33);
            Student s4 = new Student("王祖贤", 33);
    
            //把学生添加到集合
            hm.put(s1, "西安");
            hm.put(s2, "武汉");
            hm.put(s3, "郑州");
            hm.put(s4, "北京");
    
            //遍历集合
            Set<Student> keySet = hm.keySet();
            for (Student key : keySet) {
                String value = hm.get(key);
                System.out.println(key.getName() + "," + key.getAge() + "," + value);
            }
        }
    }
    

1.6LinkedHashMap集合

特点:

  • 由键决定: 有序、不重复、无索引。
  • 这里的有序指的是保证存储和取出的元素顺序一致-
  • 原理: 底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。5

LinkedHashMap没有什么需要我们特别掌握的点,它的使用方法和HashMap没有本质的区别

##TreeMap集合

1.7TreeMap集合

  • TreeMap底层是红黑树结构
  • 依赖自然排序或者比较器排序,对键进行排序
  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

两种比较器使用

  1. Comparator:

    TreeMap<Integer,String> tr = new TreeMap<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            //o1:现在这个键的值
            //o2:已经存在在的键的值
            return o1 - o2;
        }
    });
    //使用Lambda表达式
    TreeMap<Integer,String> tr = new TreeMap<>(( o1, o2)->{
                return o1 - o2
       } );
    
  2. 自定义类实现Comparable接口

    public class Student implements Comparable<Student>{
        //在接口中重写compareTo方法
         @Override
        public int compareTo(Student o) {
            //按照年龄进行排序
            int result = o.getAge() - this.getAge();
            //次要条件,按照姓名排序。
            result = result == 0 ? o.getName().compareTo(this.getName()) : result;
            return result;
        }
    }
    
    1. this:表示当前要添加的元素
    2. o:表示已经在红黑树中存在的元素

    返回值:

    • 负数:表示当前要添加的元素是小的,存左边
    • 正数:表示当前要添加的元素是大的,存右边
    • 0:表示当前要添加的元素已经存在,舍弃

    需要我们注意的是:上述代码是重写了Student类中的comapreTo方法,在方法中this.getName()方法的返回值是String类型,所以在使用的时候调用的是String中重写的比较方法

  3. 两种比较器的使用规范:

    1. 对于Java已经写好的引用类型来说:默认的比较规则是在Comparable接口中写好的,当其中的比较规则不能满足我们的需求时,我们使用comparator比较器来自定义规则
    2. 对于我们自定义的类来说,我们直接重写Comparable接口中的compareTo方法即可

TreeMap集合应用案例

  • 案例需求

    • 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
    • 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
  • 代码实现

    学生类

    public class Student implements Comparable<Student>{
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public int compareTo(Student o) {
            //按照年龄进行排序
            int result = o.getAge() - this.getAge();
            //次要条件,按照姓名排序。
            result = result == 0 ? o.getName().compareTo(this.getName()) : result;
            return result;
        }
    }
    

    测试类

    public class Test1 {
        public static void main(String[] args) {
          	// 创建TreeMap集合对象
            TreeMap<Student,String> tm = new TreeMap<>();
          
    		// 创建学生对象
            Student s1 = new Student("xiaohei",23);
            Student s2 = new Student("dapang",22);
            Student s3 = new Student("xiaomei",22);
          
    		// 将学生对象添加到TreeMap集合中
            tm.put(s1,"江苏");
            tm.put(s2,"北京");
            tm.put(s3,"天津");
          
    		// 遍历TreeMap集合,打印每个学生的信息
            tm.forEach(
                    (Student key, String value)->{
                        System.out.println(key + "---" + value);
                    }
            );
        }
    }
    

HashMap和TreeMap源码解析

2.可变参数

这是补充内容,可变参数指的是在方法中形参的数量可以变化

格式:

数据类型...名字

举例:int...args

例如:假如构造一个方法计算n个数字的相加

  1. 我们之前的方法:使用数组

    int[] arr = {1,2,3,4,5,6,7,8,9,10};
    public static int Sum(int[] arr) {
        int sum = 0;
        for (int ar:arr) {
            sum += ar;
        }
        return sum;
    }
    

    但是这样的方法不够方便

  2. 现在使用可变参数

    //测试类
    Sum(1, 2, 3,4,5);//可以传入任意个数
    
    //方法
    public static int Sum2(int...args) {
        int sum = 0;
        for (int  arg : args) {
            sum += arg;
        }
        return sum;
    }
    

    在底层实际上也是使用了数组的方法,只是Java把这些步骤帮我们省去了

    在底层也是创建了一个args名字的数组

细节:

  • 在方法的形参中至多只能出现一个可变参数
  • 当一个方法的形参列表除了可变参数还有其他参数的时候,要把可变参数放在形参列表的最后面6

3.Collections工具类

这是集合的工具类而不是集合,它是用来操作集合的

工具类的特点:

  • 没有成员变量
  • 私有化构造方法
  • 静态成员方法

3.1常用API

为了方便这里直接给上图片
请添加图片描述
需要我们掌握的是前两个

  1. addAll

    第一个形参是所有的Collection接口的实现类,方法中使用了多态的方式表示

  2. shuffle

    只适用于List集合


4.集合嵌套

在存储复杂信息的时候我们通常会使用集合的嵌套,键值对中的值存储的还是一个集合

ArrayList<String> list = new ArrayList<>();
//在集合中添加元素
Map<String, String> map = new HashMap<>();
map.put("henansheng",list)

注释:


  1. 来自黑马程序员 ↩︎

  2. put方法有细节需要注意
    put方法注意细节 ↩︎

  3. 根据键进行键值对的删除 ↩︎

  4. 同样也是Set集合,所以可以使用另外的两种遍历方法 ↩︎

  5. 这里使用的是双向链表
    请添加图片描述 ↩︎

  6. 上面的两个细节都是因为可变参数可以接收理论上实参中所有的参数,但是可变参数接收完了,其他的参数就没有实参对应了 ↩︎

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

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

相关文章

IntelliJ IDEA和MAVEN基本操作:项目和缓存存储到非C盘

为了将 IntelliJ IDEA 的所有项目和缓存存储到 C 盘以外的地方&#xff0c;以下是你需要调整的设置和步骤&#xff1a; 1. 更改项目默认存储位置 打开 IntelliJ IDEA。点击顶部菜单的 File > Settings &#xff08;Windows&#xff09;或 IntelliJ IDEA > Preferences &…

【Linux系列】`find / -name cacert.pem` 文件搜索

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

RabbitMQ基础(简单易懂)

RabbitMQ高级篇请看&#xff1a; RabbitMQ高级篇-CSDN博客 目录 什么是RabbitMQ&#xff1f; MQ 的核心概念 1. RabbitMQ 的核心组件 2. Exchange 的类型 3. 数据流向说明 如何安装RabbitQueue&#xff1f; WorkQueue&#xff08;工作队列&#xff09;&#xff1a; Fa…

《Spring Framework实战》5:Spring Framework 概述

欢迎观看《Spring Framework实战》视频教程 Spring 使创建 Java 企业应用程序变得容易。它为您提供一切 需要在企业环境中采用 Java 语言&#xff0c;并支持 Groovy 和 Kotlin 作为 JVM 上的替代语言&#xff0c;并且可以灵活地创建许多 类型的架构。从 Spring Framework 6.0 开…

有限元分析学习——Anasys Workbanch第一阶段笔记(10)桌子载荷案例分析_实际载荷与均布载荷的对比

目录 0 序言 1 桌子案例 2 模型简化 3 方案A 前处理 1&#xff09;分析类型选择 2&#xff09;材料加载 3&#xff09;约束、载荷及接触 4&#xff09;控制网格(网格大小需要根据结果不断调整) 初始计算结果 加密后计算结果 4 方案B、C 前处理 1&#xff09;分析…

Git 基础——《Pro Git》

⭐获取 Git 仓库 获取 Git 仓库有两种方式&#xff1a; 将未进行版本控制的本地目录转换为 Git 仓库。从其他服务器克隆一个已存在的 Git 仓库。 在已存在目录中初始化 Git 仓库 进入目标目录 在 Linux 上&#xff1a;$ cd /home/user/my_project在 macOS 上&#xff1a;$ c…

Java 将RTF文档转换为Word、PDF、HTML、图片

RTF文档因其跨平台兼容性而广泛使用&#xff0c;但有时在不同的应用场景可能需要特定的文档格式。例如&#xff0c;Word文档适合编辑和协作&#xff0c;PDF文档适合打印和分发&#xff0c;HTML文档适合在线展示&#xff0c;图片格式则适合社交媒体分享。因此我们可能会需要将RT…

R语言在森林生态研究中的魔法:结构、功能与稳定性分析——发现数据背后的生态故事!

森林生态系统结构、功能与稳定性分析与可视化研究具有多方面的重要意义&#xff0c;具体如下&#xff1a; 一、理论意义 ●深化生态学理论 通过研究森林生态系统的结构、功能与稳定性&#xff0c;可以深化对生态系统基本理论的理解。例如&#xff0c;生物多样性与生态系统稳定性…

Delphi+SQL Server实现的(GUI)户籍管理系统

1.项目简介 本项目是一个户籍管理系统&#xff0c;用于记录住户身份信息&#xff0c;提供新户登记&#xff08;增加&#xff09;、户籍变更&#xff08;修改&#xff09;、户籍注销&#xff08;删除&#xff09;、户籍查询、曾用名查询、迁户记录查询以及创建备份、删除备份共8…

第2课 “Hello World” 与 print

1 Hello World 2 print 函数解析 2.1 基本用法 2.2 输出多个对象 2.3 使用sep参数 2.4 使用flush参数 2.5 输出到文件 3 格式化输出 3.1 格式化输出整数 3.2 格式化输出16进制整数 3.3 格式化输出浮点数(float) 3.4 格式化输出字符串(string) 3.5 输出列表与字典 …

计算机网络(四)网络层

4.1、网络层概述 简介 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输 这些异构型网络N1~N7如果只是需要各自内部通信&#xff0c;他们只要实现各自的物理层和数据链路层即可 但是如果要将这些异构型网络互连起来&#xff0c;形成一个更大的互…

qt 窗口(window/widget)绘制/渲染顺序 QPainter QPaintDevice Qpainter渲染 失效 无效 原因

qt窗体布局 窗体渲染过程 qt中窗体渲染逻辑顺序为 本窗体->子窗体/控件 递归&#xff0c;也就是说先渲染父窗体再渲染子窗体。其中子窗体按加入时的先后顺序进行渲染。通过下方的函数调用堆栈可以看出窗体都是在widget组件源码的widgetprivate::drawwidget中进行渲染的&am…

网络安全-kail linux 网络配置(基础篇)

一、网络配置 1.查看网络IP地址&#xff0c; 我的kail&#xff1a;192.168.15.128 使用ifconfig查看kail网络连接情况&#xff0c;ip地址情况 又复制了一台kail计算机的IP地址。 再看一下windows本机&#xff1a;使用ipconfig进行查看&#xff1a; 再看一下虚拟机上的win7I…

Edge浏览器内置的截长图功能

Edge浏览器内置截图功能 近年来&#xff0c;Edge浏览器不断更新和完善&#xff0c;也提供了长截图功能。在Edge中&#xff0c;只需点击右上角的“...”&#xff0c;然后选择“网页捕获”->“捕获整页”&#xff0c;即可实现长截图。这一功能的简单易用&#xff0c;使其成为…

【NLP】语言模型的发展历程 (1)

语言模型的发展历程系列博客主要包含以下文章&#xff1a; 【NLP】语言模型的发展历程 (1)【NLP】大语言模型的发展历程 (2) 本篇博客是该系列的第一篇&#xff0c;主要讲讲 语言模型&#xff08;LM&#xff0c;Language Model&#xff09; 的发展历程。 文章目录 一、统计语…

【ASP.NET学习】ASP.NET MVC基本编程

文章目录 ASP.NET MVCMVC 编程模式ASP.NET MVC - Internet 应用程序创建MVC web应用程序应用程序信息应用程序文件配置文件 用新建的ASP.NET MVC程序做一个简单计算器1. **修改视图文件**2. **修改控制器文件** 用新建的ASP.NET MVC程序做一个复杂计算器1.创建模型&#xff08;…

蓝桥云客第 5 场 算法季度赛

题目&#xff1a; 2.开赛主题曲【算法赛】 - 蓝桥云课 问题描述 蓝桥杯组委会创作了一首气势磅礴的开赛主题曲&#xff0c;其歌词可用一个仅包含小写字母的字符串 S 表示。S 中的每个字符对应一个音高&#xff0c;音高由字母表顺序决定&#xff1a;a1,b2,...,z26。字母越靠后…

计算机网络 (37)TCP的流量控制

前言 计算机网络中的TCP&#xff08;传输控制协议&#xff09;流量控制是一种重要机制&#xff0c;用于确保数据在发送方和接收方之间的传输既高效又稳定。 一、目的 TCP流量控制的主要目的是防止发送方发送数据过快&#xff0c;导致接收方无法及时处理&#xff0c;从而引起数据…

【Elasticsearch7.11】postman批量导入少量数据

JSON 文件内的数据格式&#xff0c;json文件数据条数不要过多&#xff0c;会请求参数过大&#xff0c;最好控制再10000以内。 {"index":{"_id":"baec07466732902d22a24ba01ff09751"}} {"uuid":"baec07466732902d22a24ba01ff0975…

Spring Boot 支持哪些日志框架

Spring Boot 支持多种日志框架&#xff0c;主要包括以下几种&#xff1a; SLF4J (Simple Logging Facade for Java) Logback&#xff08;默认&#xff09;Log4j 2Java Util Logging (JUL) 其中&#xff0c;Spring Boot 默认使用 SLF4J 和 Logback 作为日志框架。如果你需要使…