java集合-Map接口

        Map接口可以将键(Key)映射到值(Value)的对象,一个键可以映射到最多一个值。这意味着在Map中,每个键 (K) 都是唯一的,但值 (V) 可以重复。

        Set接口在内部也是使用键值对(K-V)的方式来存储元素的(这是基于它们底层使用的Map实现)。在Set接口中,键(K)就是Set中存储的元素本身,而值(V)通常是一个固定的占位符对象,通常是内部类的一个实例,例如HashMap中的PRESENT,它是一个静态的Object实例。

Map介绍

        1、Map和Collection并列存在,用于保存具有映射关系的数据(K-V双列元素)。
        2、Map中的 key 和 value 可以是任何引用类型的数据,会封装到 HashMap$Node 对象中
        3、Map中的 key 不允许重复(value可重复),如有重复,则会将新的K-V替换掉原本的value值
        4、Map中的K和V都可为空,但K只能有一个为空,V可以有多个为空

        Map myMap = new HashMap();
        myMap.put("key1","value1");
        myMap.put(null,null);//k和v都为空
        myMap.put(null,"value");//k也为空,v会替换之前的值
        myMap.put("key2",null);//v为空
        myMap.put("key3",null);//v再次为空

        此时Map:{key1=value1, null=value, key2=null, key3=null}

        5、一般使用String来作Map的key,其他类型的数据也可,但不推荐
        6、一对k-v存放在一个HashMap$Node = newNode(hash, key, value, null)中
        7、为方便遍历,还会创建EntrySet集合,该集合存放的元素类型为 Entry ,而每一个Entry实际存放的是HashMap$Node(因为static class Node<K,V> implements Map.Entry<K,V>),以便使用Entry的 getKey 和 getValue 方法,同时还提供了 KeySet (属Set接口) 和 values (属Collection接口) 类以便单独查看K和V

常用方法

        1、put():添加元素,依次输入k和v的值
        2、remove():删除指定元素,有两种重载版本
remove(Object key):删除该键下的所有元素,删除成功返回该k对应的v值,失败返回null;remove(Object key,Object value):只有当键存在且与给定的值相匹配时,才会从映射中移除该键值对。成功返回true,失败返回false
       
3、get():查看元素,输入k,返回对应的v值,不存在则返回null,返回的元素类型由value的类型确定
        4、size():查看长度,返回该集合的元素个数
        5、isEmpty():是否为空:查看该集合是否存在元素
        6、clear():清空该集合内的所有元素
        7、containsKey():查找该键是否存在;containsValue()查找该值是否存在

遍历方式

        上文我们介绍了为方便遍历,还会创建EntrySet集合以及对应的KeySet和values,所以其至少包含三种遍历方式。

一、通过Key遍历

        Map myMap = new HashMap();
        //添加元素......
        Set keySet = myMap.keySet();//创建Set类实例接收keyset集合
        for (Object o :keySet) {//增强for循环
            System.out.println(o+"-"+myMap.get(o));
        }//o为key,get查看key对应的value值
        Iterator iterator = keySet.iterator();//迭代器
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next+"-"+myMap.get(next));
        }

二、遍历Value

        Map myMap = new HashMap();
        //添加元素......
        Collection values = myMap.values();//创建Collection类实例接收values集合
        for (Object o :values) {//增强for循环
            System.out.println(o);
        }
        Iterator iterator = values.iterator();//迭代器
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);

三、通过EntrySet遍历

        这一类型略微复杂,上文我们提到系统创建的EntrySet集合存放的元素类型为 Entry ,而每一个Entry实际存放的是Node,以便使用Entry的 getKey 和 getValue 方法。
        所以我们可以直接输出Node类型的数据,也可将其转为编译类型Entry,再使用Entry的getKey 和 getValue 方法来单独查看Key或Value。

        Map myMap = new HashMap();
        //添加元素......
        Set entrySet = myMap.entrySet();//创建Set类实例接收entrySet集合
        for (Object entry :entrySet) {//增强for循环
            //此时entry编译类型为Object,运行类型为Node
            System.out.println(entry);//直接输出Node类型元素
            Map.Entry newEntry=(Map.Entry)entry;//将entry的编译类型由Object转为Entry向下转型
            //此时entry编译类型为Entry,运行类型为Node,可调用getKey 和 getValue方法
            System.out.println("[key="+newEntry.getKey()+"   value="+newEntry.getValue()+"]");
        }
        Iterator iterator = entrySet.iterator();//迭代器
        while (iterator.hasNext()) {
            //同理
            Object next =  iterator.next();
            System.out.println(next);
            Map.Entry newEntry=(Map.Entry)next;
            System.out.println("[key="+newEntry.getKey()+"   value="+newEntry.getValue()+"]");
        }

        例题:使用HashMap添加多个员工对象,要求:
1、键(key)为员工id,值(value)为员工对象。
2、自定义员工类,包含姓名、工资、员工id。
3、使用至少两种遍历方式输出工资>18000的员工

public class Go {
    public static void main(String[] args) {
        HashMap myMap = new HashMap();
        Employee staff1 = new Employee("一一", 3000, "1st");
        Employee staff2 = new Employee("二二", 1000, "2nd");
        Employee staff3 = new Employee("三三", 1500, "3rd");
        Employee staff4 = new Employee("四四", 2000, "4th");
        myMap.put(staff1.getId(), staff1);
        myMap.put(staff2.getId(), staff2);
        myMap.put(staff3.getId(), staff3);
        myMap.put(staff4.getId(), staff4);
        System.out.println("———————————————通过EntrySet遍历———————————————");
        for (Object Entry : myMap.entrySet()) {
            Map.Entry newEntry = (Map.Entry) Entry;
            Employee emp = (Employee) newEntry.getValue();
            if (emp.getSal() > 1800)
                System.out.println(newEntry);
        }
        System.out.println("————————————————通过KeySet遍历————————————————");
        for (Object key : myMap.keySet()) {
            Employee emp=(Employee)myMap.get(key);
            if (emp.getSal()>1800)
            System.out.println(key+"="+myMap.get(key));
        }

        System.out.println("————————————————通过values遍历————————————————");
        for (Object o : myMap.values()) {
            Employee emp=(Employee)o;
            if (emp.getSal()>1800)
                System.out.println(emp.getId()+"="+o);
        }
        System.out.println("————————————————通过迭代器遍历————————————————");
        Iterator iterator = myMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry newNext = (Map.Entry) iterator.next();
            Employee employee = (Employee) newNext.getValue();
            if (employee.getSal() > 1800)
                System.out.println(newNext);
        }
    }
}
class Employee {省略......}

执行结果

———————————————通过EntrySet遍历———————————————
1st=Employee{name='一一', sal=3000.0, id='1st'}
4th=Employee{name='四四', sal=2000.0, id='4th'}
————————————————通过KeySet遍历————————————————
1st=Employee{name='一一', sal=3000.0, id='1st'}
4th=Employee{name='四四', sal=2000.0, id='4th'}
————————————————通过values遍历————————————————
1st=Employee{name='一一', sal=3000.0, id='1st'}
4th=Employee{name='四四', sal=2000.0, id='4th'}
————————————————通过迭代器遍历————————————————
1st=Employee{name='一一', sal=3000.0, id='1st'}
4th=Employee{name='四四', sal=2000.0, id='4th'}

HashMap

        由于HashMap与Map的特点高度重和,因此仅简单总结一下:HashMap是Map接口使用频率最高的实现类;以K-V的方式来存储Node型数据,k不能重复但v可以重复,再次添加已有的k会覆盖原k-v,可添加null;HashMap未实现同步,因此线程是不安全的(无synchronized)。与HashSet相同,其取出的顺序也不能保证有序,因为其底层也是根据hash值来存储的。
        1、HashMap的底层维护了Node类型的数组table,默认为null;
        2、首次添加元素数组大小为16,加载因子为0.75(LoadFactor),临界值为16*0.75=12。之后再扩容则直接扩至2倍;当哈希桶(链表)添加第9个元素时,数组会进行2倍扩容,之后每多添加一个扩容一次,直至满足64个元素,开始树化。
        3、添加k-v时,通过hash值得到索引,判断该索引处是否有元素,无则直接添加,有则先判断两k是否相等,相等则替换v,不相等则判断为树结构还是链表结构并进行相应操作,容量不足则扩容;

Hashtable

        Hashtable和HashMap属同一级,都实现了Map接口,其大体也与HashMap相同:
1、存放的元素为键值对K-V。
2、常用方法基本相同。
        但也有一定的区别:
1、Hashtable的键和值都不能为null,否则会抛出空指针异常。HashMap可以为null
2、Hashtable为线程安全、HashMap为非线程安全(无synchronized)
3、Hashtable的底层维护了Hashtable$Entry,初始大小为11,加载因子为0.75(LoadFactor),临界值为11*0.75=8,之后再扩容则直接扩至(2倍+1);

Properties

        Properties为Hashtable的子类,也是使用键值段来保存数据。Properties还可用于从XXX.properties文件中加载数据到Properties类对象,并进行读取和修改。

        XXX.properties文件通常为配置文件,后续IO流则会提及

        比如在保存数据库密码时,如果将账号密码放入java文件中,那么每次修改都需重新编译,而保存在Properties文件中,修改相对简单

        增/改:put()添加一对键值,如键已存在,则修改对应的值
        删:remove()两种重载,1,remove(Object key)删除指定键所对应的所有对象;2 remove(Object key,Object value)删除指定键值对
        查:两种方法:1、get()查找该键所对应的所有值,查找到则返回Object类,未找到返回null;2、pro.getProperty()两种重载:a、pro.getProperty(String key)同get方法,但只能查找String,返回值也为String,b、pro.getProperty(String key,String xxx)查找失败则返回String xxx,查找成功则等同上文

        Properties pro = new Properties();
        pro.put(111,"第一");
        pro.put(222,"第二");
        pro.put(333,"第三");
        pro.remove(111);
        pro.put(222,"新元素");
        System.out.println(pro);
        System.out.println(pro.get(222));
        System.out.println(pro.getProperty("222","该元素不存在"));

 执行结果:

{333=第三, 222=新元素}
新元素
该元素不存在

TreeMap

        其与TreeSet极其相似,在此仅举例说明

        //使用无参构造器
        TreeMap ts = new TreeMap();
        ts.put("jjjj", "aaaa");
        ts.put("aaaa", "aaaa");
        ts.put("cccc", "aaaa");
        ts.put("kkkk", "aaaa");
        ts.put("kkkk", "aaaa");//重复元素不添加,仅替换value
        System.out.println(ts);
输出:{aaaa=aaaa, cccc=aaaa, jjjj=aaaa, kkkk=aaaa}
        //自定义比较器-----------------------------
        TreeMap ts = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        });
        ts.put("j", "aaaa");
        ts.put("aa", "aaaa");
        ts.put("ccc", "aaaa");
        ts.put("kkkk", "aaaa");
        ts.put("pppp", "aaaa");//长度重复不添加,仅替换value
        System.out.println(ts);
输出:{j=aaaa, aa=aaaa, ccc=aaaa, kkkk=aaaa}

        当添加第一个元素时,也会调用比较器,但此时数组内只有一个元素,所以系统会将两值的key相比较,此举只起检查是否为空值的作用,对结果无影响。 

总结:如何选择类

        在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类的特性进行选择:

        先判断存储的类型(一组对象[单列]还是一组键值对[双列])

一、一组对象[单列]:Collectionj接口

  1. 允许重复:List
    1. 增删少:LinkedList(底层维护了一个双向链表)
    2. 增删多:ArrayList(底层维护了Object类型的可变数组)
  2. 不允许重复:Set
    1. 无序:HashSet(底层为HashMap,维护了一个哈希表,即数组+链表+红黑树)
    2. 排序:TreeSet
    3. 插入取出顺序一致:LinkedHashSet(维护数组+链表,底层为LinkedHashMap)

二、一组键值对[双列]:Map

  1. 无序:HashMap(jdk8以上为数组+链表+红黑树)
  2. 排序:TreeMap
  3. 插入取出顺序一致:LinkedHashMap(维护数组+链表)
  4. 便于读取修改:Properties

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

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

相关文章

使用离火插件yoloV8数据标注,模型训练

1. 启动 2.相关配置 2.1 data.yaml path: D:/yolo-tool/yaunshen-yolov8/YOLOv8ys/YOLOv8-CUDA10.2/1/datasets/ceshi001 train: images val: images names: [蔡徐坤,篮球] 2.2 cfg.yaml # Ultralytics YOLOv8, GPL-3.0 license # Default training settings and hyp…

VS Code使用Git Bash终端

Git Bash可以运行linux命令&#xff0c;在VS Code的终端界面&#xff0c;找到号旁边的箭头&#xff0c;就能直接切换了 当然&#xff0c;前提是安装了Git Bash&#xff0c;并且在资源管理器里&#xff0c;能鼠标右键出"Git Bash Here"

C语言 | Leetcode C语言题解之第438题找到字符串中所有字母异位词

题目&#xff1a; 题解&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ /* *int strCmpn&#xff1a;比较滑动窗口和字符串的相同值 char * s&#xff1a;字符串s&#xff0c;滑动窗口的位置 char * p&#xff1a;字符串p&#…

Python 课程21-Django

前言 在当今互联网时代&#xff0c;Web开发已成为一项必备技能。而Python作为一门简洁、高效的编程语言&#xff0c;其Web框架Django以其强大的功能和快速开发的特点&#xff0c;受到了广大开发者的青睐。如果你想深入学习Django&#xff0c;构建自己的Web应用&#xff0c;那么…

云中红队系列 | 使用 AWS API 配置Fireprox进行 IP轮换

在渗透测试评估期间&#xff0c;某些活动需要一定程度的自动化&#xff0c;例如从 LinkedIn 等网站抓取网页以收集可用于社会工程活动、密码喷洒登录门户或测试时盲注的有效员工姓名列表网络应用程序。但是&#xff0c;从单个源 IP 地址执行这些活动可能会导致在测试期间被拦截…

深度学习—神经网络基本概念

一&#xff0c;神经元 1.生物神经元与人工神经元 1.1神经元是人脑的基本结构和功能单位之一。人脑中有数1000亿个神经元&#xff0c;其功能是接受&#xff08;树突&#xff09;&#xff0c;整合&#xff08;细胞体&#xff09;&#xff0c;传导&#xff08;轴突&#xff09;和…

电脑usb接口封禁如何实现?5种禁用USB接口的方法分享!(第一种你GET了吗?)

“防患于未然&#xff0c;安全始于细节。”在信息技术飞速发展的今天&#xff0c;企业的信息安全问题日益凸显。 USB接口作为数据传输的重要通道&#xff0c;在带来便利的同时&#xff0c;也成为了数据泄露和安全风险的高发地。 因此&#xff0c;对电脑USB接口进行封闭管理&a…

【OceanBase 诊断调优】—— GC问题根因分析

GC 流程涉及到 RS 的状态切换和 LS 的资源安全回收&#xff0c;流程上较长。且 GC 线程每个租户仅有一个&#xff0c;某个日志流 GC Hang 死时会卡住所有其余日志流的 GC&#xff0c;进而造成更大的影响。 本文档会帮助大家快速定位到 GC 故障的模块&#xff0c;直达问题核心。…

Redis篇(环境搭建)

目录 一、安装包 1. Windows版下载地址 2. Linux版下载地址 二、安装Redis 1. 在Linux中安装Redis 2. 在Windows中安装Redis 3. 细节问题 三、Redis服务启动 1. 默认启动 2. 指定配置启动 3. 开机自启 四、Redis服务停止 1. Linux系统中启动和停止Redis 2. Window…

SLF4J报错log4j又报错

项目场景&#xff1a; 搭建一个spirngboot项目&#xff0c;启动运行时&#xff0c;SLF4J报错 解决后 ~ log4j又报错了。 问题描述 首先是SLF4J报错了&#xff0c;解决完SL4J报错问题后&#xff0c;再次启动项目&#xff0c;log4j又报错了 。。。 报错信息&#xff1a; SLF4J…

Go语言匿名字段使用与注意事项

1. 定义 Go语言支持一种特殊的字段只需要提供类型而不需要写字段名的字段&#xff0c;称之为匿名字段或者嵌套字段。 所谓匿名字段实际上是一种结构体嵌套的方式&#xff0c;所以也可以称作嵌套字段。 这种方式可以实现组合复用&#xff0c;即通过匿名字段&#xff0c;结构体…

说说海外云手机的自动化功能

在全球社交媒体营销中&#xff0c;通过自动化功能&#xff0c;企业不再需要耗费大量时间和精力手动监控和操作每台设备。这意味着&#xff0c;企业可以显著提升效率、节省成本&#xff0c;同时减少对人力资源的依赖。那么&#xff0c;海外云手机的自动化功能具体能带来哪些优势…

使用ucharts写的小程序页面柱状图上方没有数字

使用uCharts官网 - 秋云uCharts跨平台图表库写的柱状图如何让柱子上放没有数据 更改前 更改后 使用uCharts官网 - 秋云uCharts跨平台图表库 写的小程序图表&#xff0c;无论是柱状图还是折线图添加一个 dataLabel: false, // 不显示数据 九可以实现不显示数据 const opts …

IDEA Dependency Analyzer 分析 maven 项目包的依赖

一、场景分析 javax.validation 是我们 SpringMVC 常用的数据校验框架。但是 javax.validation 是一个规范&#xff08;Java Bean Validation&#xff0c;简称 JSR 380&#xff09;&#xff0c;它并没有具体的实现&#xff0c;它的常用实现&#xff0c;是hibernate-validator。…

数据结构 - 数组

今天我们将开始第一个数据类型-数组的学习。 经常会看到这样的问题&#xff0c;怎么学习数据结构&#xff0c;我的答案是搞清楚具体数据结构对应的抽象数据类型ADT&#xff0c;抛开语言层面自带的数据类型&#xff0c;然后自己从头 实现一遍。 其实数据结构没多复杂&#xff…

基于SSM+小程序的医院核酸检测服务管理系统(医院2)(源码+sql脚本+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM小程序的医院核酸检测服务管理系统实现了管理员、用户管理、普通管理员、医护人员。 1、管理员实现了首页、用户管理、医护人员管理、普通管理员、通知公告管理、疫苗接种管理、核…

华为GaussDB数据库(单机版)在ARM环境下的安装指南

一、软件版本 机器配置&#xff1a;8核16G&#xff0c;CPU: Huawei Kunpeng 920 2.9GHz操作系统&#xff1a;EulerOS 2.8 64bit with ARM数据库版本&#xff1a;GaussDB Kernel 505.1.0 build 44f4fa53 二、部署流程 2.1 新建用户 ① 以omm用户为例&#xff0c;添加一个omm用…

11. Map和Set

一、二叉搜索树 1. 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根…

IvorySQL 3.4 来了

9 月 26 日&#xff0c;IvorySQL 3.4 发版。本文将带大家快速了解新版本特性。 IvorySQL 3.4 发版说明 IvorySQL 3.4 基于 PostgreSQL 16.4&#xff0c;修复了多个问题&#xff0c;并增强多项功能。 PostgreSQL 16.4 的变更 在未经授权时防止 pg_dump 执行&#xff0c;并引入一…

Qt-QTableWidget多元素控件(37)

目录 描述 QTableWidget 方法 QTableWidgetItem 信号 QTableWidgetItem 方法 使用 图形化界面操作 代码操作 描述 这是一个表格控件&#xff0c;表格中的每一个单元格&#xff0c;都是一个 QTableWidgetItem 对象 QTableWidget 方法 item(int row,int column)根据⾏数…