当前位置: 首页 > news >正文

Java-集合(5)

Map接口

JDK8

Map接口实现子类的特点

  1. Map和Collection是并列关系,Map用于保存具有映射关系的数据:Key-Value
  2. Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
  3. Map中的key不允许重复,原因和HashSet一样
  4. Map中的value可以重复
  5. Map的key可以为null,value也可以为null,但是key只能有一个null,value可以有多个null只要key不同就行
  6. 常用String类为Map的key
  7. key和value之间存在单向一对一关系,即通过key找到对应的value。可以理解为key相当于身份证号,value是对应的人,人可以重复名字样貌等,但是身份证不能重复。
  8. 当加入一个重复的key和不重复的value时,相当于替换

测试:

public class test1 {public static void main(String[] args) {Map map = new HashMap();map.put("nbo1","张三");map.put("nbo2","李四");map.put("nbo3","王五");map.put("nbo1","李向");System.out.println(map);}
}

运行结果:
{nbo2=李四, nbo1=李向, nbo3=王五}

在之前Collection接口实现集合类,都是使用key来直接保存存储的数据。而Map接口实现集合类会使用key和value两个相互映射来保存数据,key可以看作是一个序号或者身份证号,value才是真正保存的数据

理解:Map存放的key-value是放在一个Node中的,又因为Node实现了Entry接口,所以也说一对k-v也是一个Entry**

在这里插入图片描述
我们知道当使用Map实现集合类存放了一个元素时,会有key和value,也就是键和值,键key可以看作是一个序号,值valuie可以看作是内容,一个序号对应一个内容,而这两个东西是存放在一个Node节点中的。但是因为Map不是Collection接口,Map没有实现iterator接口,所以要遍历不是很方便。因此在添加元素时除了会保存到table数组时,还会做一件事情就是保存到一个EntrySet集合中,EntrySet集合中的保存类型不是Node类型而是Entry类型。
但是这里的意思不是说把table中的数组都复制一份到EntrySet集合中,而是单纯的引用,也就是把EntrySet中的一个个Entry指向的还是table中的一个个Node。而为什么要做这么一件事呢,这是因为在EntrySet集合中保存的key是Set接口类型的value是Collection接口类型的,当然实际运行类型还是Node,只不过这样就可以使用迭代器了。

public class test1 {public static void main(String[] args) {Map map = new HashMap();map.put("nbo1","张三");map.put("nbo2","李四");map.put("nbo3","王五");map.put("nbo1","李向");Set set = map.entrySet();for (Object obj:set) {Map.Entry entry = (Map.Entry) obj;System.out.println(entry.getClass());System.out.println(entry.getKey()+"-"+entry.getValue());}}
}

运行结果:
class java.util.HashMapNodenbo2−李四classjava.util.HashMapNode nbo2-李四 class java.util.HashMapNodenbo2李四classjava.util.HashMapNode
nbo1-李向
class java.util.HashMap$Node
nbo3-王五

Map接口实现类的常用方法

口语说法:key:键 ———— value:值

  1. put(key,value);添加,当再次添加同一个键,但是值不同时,会对值进行替换
  2. remove(key);根据键删除这对键和值
  3. get(key);根据键获取值
  4. size();获取当前集合的元素个数
  5. isEmpty():判断当前集合元素个数是否为0
  6. containsKey(key);查找传入的键是否存在
  7. clear:清除集合所有元素,归0

使用演示

public class test2 {public static void main(String[] args) {Map map = new HashMap();//        1. put(key,value);添加,当再次添加同一个键,但是值不同时,会对值进行替换map.put("no1","李青");map.put("no2","绿意");map.put("no1","李青");System.out.println(map);
//        2. remove(key);根据键删除这对键和值map.remove("no1");System.out.println(map);
//        3. get(key);根据键获取值System.out.println(map.get("no2"));
//        4. size();获取当前集合的元素个数System.out.println(map.size());
//        5. isEmpty():判断当前集合元素个数是否为0System.out.println(map.isEmpty());
//        6. containsKey(key);查找传入的键是否存在System.out.println(map.containsKey("no2"));
//        7. clear:清除集合所有元素,归0map.clear();System.out.println(map);}
}

运行结果:
{no2=绿意, no1=李青}
{no2=绿意}
绿意
1
false
true
{}

Map接口实现类的六大遍历方式

上面了解到了map存入的数据还会有一个EntrySet集合指向table数组中的数据,所以遍历也是围绕这个来操作
Map实现接口可以分为三大类:每类有两种方式
1.获取键key,再通过键来获取值value
2.直接获取值value,但是无法通过值value获取key,所以只能输出value
3.通过EntrySet,同时获取到键和值

遍历用到的方法

  1. KeySet:获取所有键
  2. entrySet:获取所有键和值k-v
  3. values:获取所有值

演示:

public class test3 {public static void main(String[] args) {Map map = new HashMap();map.put("no1","淘宝");map.put("no2","天猫");map.put("no3","京东");//第一类:获取所有键,再通过get方法获取值。//第一种方式:获取键后使用增强forSystem.out.println("第一种");Set set = map.keySet();for (Object key:set) {System.out.println(key+"-"+map.get(key));}System.out.println("第二种");//第二种方式:获取键后,使用迭代器Iterator iterator = set.iterator();while (iterator.hasNext()) {Object next =  iterator.next();System.out.println(next+"-"+map.get(next));}//第二类:获取所有值//第三种方式:增强for,直接输出valueSystem.out.println("第三种");Collection value = map.values();for (Object o: value) {System.out.println(o);}//第四种:使用迭代器直接输出System.out.println("第四种");Iterator iterator2 = value.iterator();while (iterator2.hasNext()) {Object next =  iterator2.next();System.out.println(next);}//第三类:获取所有键和值,再向下转型成Entry,使用它的getKey和getValue方法//第五种:获取所有键和值,增强for操作System.out.println("第五种");Set entrySet = map.entrySet();for (Object e:entrySet) {Map.Entry entry = (Map.Entry) e;System.out.println(entry.getKey()+"-"+entry.getValue());}//第六种:迭代器操作System.out.println("第六种");Iterator iterator1 = entrySet.iterator();while (iterator1.hasNext()) {Object next =  iterator1.next();Map.Entry entry = (Map.Entry) next;System.out.println(entry.getKey()+"-"+entry.getValue());}}
}

运行结果:
第一种
no2-天猫
no1-淘宝
no3-京东
第二种
no2-天猫
no1-淘宝
no3-京东
第三种
天猫
淘宝
京东
第四种
天猫
淘宝
京东
第五种
no2-天猫
no1-淘宝
no3-京东
第六种
no2-天猫
no1-淘宝
no3-京东

Map小练习

使用HashMap添加三个员工对象,要求:
键:员工id
值:员工对象

且遍历显示工资18000的员工至少使用两种遍历方式
员工类:姓名,工资,员工id

public class test4 {@SuppressWarnings({"all"})public static void main(String[] args) {HashMap map = new HashMap();staff s1 = new staff(01,"李四",16000);staff s2 = new staff(02,"王五",23000);staff s3 = new staff(03,"赵三",12000);staff s4 = new staff(04,"李明",19000);map.put(s1.id,s1);map.put(s2.id,s2);map.put(s3.id,s3);map.put(s4.id,s4);//第一种:获取直接获取所有值,判断运行类型是否是staff,如果是就向下转型,再判断薪水决定是否输出Collection c = map.values();for (Object value:c) {if (value instanceof staff){staff s = (staff) value;if (s.sal>18000){System.out.println(s);}}}//第二种:直接获取所有键和值Set entrySet = map.entrySet();for (Object entry:entrySet) {Map.Entry entry1 = (Map.Entry) entry;staff s = (staff) entry1.getValue();if (s.sal>18000){System.out.println(s);}}}
}
class staff{String name;int id;double sal;public staff(int id,String name,double sal) {this.name = name;this.id = id;this.sal = sal;}@Overridepublic String toString() {return "staff{" +"name='" + name + '\'' +", id=" + id +", sal=" + sal +'}';}
}

HashMap小结

  • Map接口的常用实现类:HashMap,Hashtable,Properties,ThreeMap
  • HashMap是Map接口使用频率最高的实现类
  • HashMap是以key-value对的方式来存储数据的
  • key不能重复,但是值可以重复,运行使用null作为存入的数据
  • 如果添加相同的key,则会覆盖原来的key-value,等同于替换
  • 与HashSet一样,HashMap不保证映射的顺序,因为底层是以hash表的方式来存储的(jdk8的hashMap底层:数组+链表+红黑树)
  • HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

HashMap底层机制及源码刨析

扩容机制

  1. HashMap底层维护了Node类型的数组table,默认为null
  2. 当创建对象时,将加载因子(loadfactor)初始化为0.75.也就是当table数组存放的元素数到达整体数组大小的75%时,就会进行扩容
  3. 当添加k-y时,会先通过key的哈希值得到在table的索引,然后判断该索引是否有元素,如果没有则直接添加,如果有元素就判断该位置的元素key和准备添加的key是否相等,如果相等则直接替换value,如果不相等则判断是树结构还是链表结构,如果是链表结构就直接与下一个元素判断。
  4. 第一次添加,需要扩容table数组容量为16,扩容临界值(threshold)为12,(16*0.75)
  5. 非第一次扩容就是扩容table容量为原来的2倍,临界值也为原来的2倍,以此类推
  6. 在java8中,如果一条链表的元素超过了8个且table的大小>=64就会进行树化,如果链表元素超过8个,但是table数组的大小还未超过64,那么就会先进行数组扩容,直到数组大小到达64才会进行树化

Hashtable

在这里插入图片描述

Hashtable也是Map接口的实现类,与HashMap是同级关系

Hashtable基本介绍

  1. 存放的元素也是键和值:key-value
  2. Hashtable的k-v都不能存放null,负责会抛出异常
  3. Hashtable的使用方法基本上和HashMap一致
  4. Hashtable是线程安全的,HashMap是线程不安全的

Hashtable底层介绍

初始

  1. 底层由数组Hashtable$Entry[]初始化大小为11
  2. 初始临界值threeshold 8 = 11*0.75,所以也是到75%就扩容
  3. Hashtable除了第一次初始化大小,后面扩容机制为 *2+1.

Hashtable和HashMap的选择

实现类出现版本线程安全效率是否可以存null
HashMap1.2不安全允许
Hashtable1.0安全较低不允许

Properties

Properties基本介绍

  1. Properties类继承于Hahstable类,同样实现了Map接口,也是一种键key-值value的形式保存数据
  2. Properties的使用特点和Hashtable类似
  3. Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象进行读取和修改(在IO流说明)

Properties的增删改查

public class test5 {public static void main(String[] args) {Properties properties = new Properties();//增加properties.put("no1",100);properties.put("no2",200);//删除,根据key,删除key-valueproperties.remove("no1");System.out.println(properties);//改(替换)properties.put("no2",90);System.out.println(properties);//查,根据key获取valueSystem.out.println(properties.get("no2"));}
}

相关文章:

Java-集合(5)

Map接口 JDK8 Map接口实现子类的特点 Map和Collection是并列关系,Map用于保存具有映射关系的数据:Key-ValueMap中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中Map中的key不允许重复,原因和HashSet一样Map…...

研制过程评审活动(四)设计定型阶段

1、设计定型阶段主要任务 设计定型的主要任务是对武器装备性能和使用要求进行全面考核,以确认产品是否达到《研制任务书》和《研制合同》的要求。   设计定型阶段应最终确定《产品规范》、《工艺规范》和《材料规范》的正式版本,并形成正式的全套生产图样、有关技术文件及目…...

【Linux】进程替换

文章目录进程程序替换替换原理替换函数函数返回值函数命名理解在makefile文件中一次生成两个可执行文件总结:程序替换时运行其它语言程序进程程序替换 程序要运行要先加载到内存当中 , 如何做到? 加载器加载进来,然后程序替换 为什么? ->冯诺依曼 因为CPU读取数据的时候只…...

LeetCode171-Excel表列序号(进制转换问题)

LeetCode171-Excel表列序号1、问题描述2、解题思路:进制转换3、代码实现1、问题描述 给你一个字符串columnTitle,表示Excel表格中得列名称。返回该列名称对应得列序号。 例如: A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 …...

React SSR

ReactDOMServer 参考链接:https://zh-hans.reactjs.org/docs/react-dom-server.html ReactDOMServer 对象允许你将组件渲染成静态标记。通常,它被使用在 Node 服务端上 // ES modules import * as ReactDOMServer from react-dom/server; // CommonJS v…...

如何系统地优化页面性能

页面优化,其实就是要让页面更快地显示和响应。由于一个页面在它不同的阶段,所侧重的关注点是不一样的,所以如果要讨论页面优化,就要分析一个页面生存周期的不同阶段。 通常一个页面有三个阶段:加载阶段、交互阶段和关…...

Vulnhub 渗透练习(八)—— THE ETHER: EVILSCIENCE

环境搭建 环境下载 靶机和攻击机网络适配都选 NAT 即可。 信息收集 主机扫描 两个端口,22 和 80,且 apache httpd 2.4.0~2.4.29 存在换行解析漏洞。 Apache HTTPD是一款HTTP服务器,它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中…...

华为OD机试题 - 水仙花数 2(JavaScript)| 代码+思路+重要知识点

最近更新的博客 华为OD机试题 - 字符串加密(JavaScript) 华为OD机试题 - 字母消消乐(JavaScript) 华为OD机试题 - 字母计数(JavaScript) 华为OD机试题 - 整数分解(JavaScript) 华为OD机试题 - 单词反转(JavaScript) 使用说明 参加华为od机试,一定要注意不要完全背…...

字符设备驱动基础(二)

目录 一、五种IO模型------读写外设数据的方式 二、阻塞与非阻塞 三、多路复用 3.1 应用层:三套接口select、poll、epoll 3.2 驱动层:实现poll函数 四、信号驱动 4.1 应用层:信号注册fcntl 4.2 驱动层:实现fasync函数 一、…...

看见统计——第三章 概率分布

看见统计——第三章 概率分布 参考 https://github.com/seeingtheory/Seeing-Theory中心极限定理 概率分布描述了随机变量取值的规律。 随机变量Random Variables 🔥 定义:将样本空间中的结果映射到实数的函数 XXX 称为随机变量(random variable)&a…...

【基于众包标注的语文教材句子难易度评估研究 论文精读】

基于众包标注的语文教材句子难易度评估研究 论文精读信息摘 要0 引言1 相关研究2 众包标注方法3 语料库构建3.1 数据收集3.1 基于五点量表的专家标注3.3 基于成对比较的众包标注4 特征及模型4.1 特征抽取4.2 模型与实验设计4.2.1 任务一:单句绝对难度评估4.2.2 任务二:句对相对…...

实例五:MATLAB APP design-APP登录界面的设计

一、APP 界面设计展示 注:在账号和密码提示框输入相应的账号和密码后,点击登录按钮,即可跳转到程序中设计的工作界面。 二、APP设计界面运行结果展示...

作用域和闭包:

1、LHS和RHS查询编译一段代码,需要js引擎和编译器(js引擎负责整个程序运行时所需的各种资源的调度,编译器只是js引擎的一部分,负责将JavaScript源码编译成机器能识别的机器指令,然后交给引擎运行)编译的过程…...

Vue常见面试题?

1、说说你对SPA单页面的理解,它的优缺点是什么? SPA(single-page application)仅在Web页面初始化时加载相应的HTML、JavaScript和CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机…...

前端借助Canvas实现压缩图片两种方法

一、具体代码 1、利用canvas压缩图片方法一 // 第一种压缩图片方法(图片base64,图片类型,压缩比例,回调函数)// 图片类型是指 image/png、image/jpeg、image/webp(仅Chrome支持)// 该方法对以上三种图片类型都适用 压缩结果的图片base64与原类型相同// …...

2023年美赛C题Wordle预测问题二建模及Python代码详细讲解

更新时间:2023-2-19 相关链接 (1)2023年美赛C题Wordle预测问题一建模及Python代码详细讲解 (2)2023年美赛C题Wordle预测问题二建模及Python代码详细讲解 (3)2023年美赛C题Wordle预测问题三、四…...

【算法】双指针

作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下来🐾 文章目录1.双指针分类2.双指针思想3.双指针应用1.双指针分类 常见问题分类 (1) 对于一个序列,用两个指针维护一段区间, 比如快速排序。 …...

Flutter-Widget-学习笔记

Widget 是整个视图描述的基础。 参考:https://docs.flutter.dev/resources/architectural-overview Widget 到底是什么呢? Widget 是 Flutter 功能的抽象描述,是视图的配置信息,同样也是数据的映射,是 Flutter 开发框…...

easyExcel 写复杂表头

写模板 模板图片: 实体类(这里没有用Data 是因为Lombok和easyExcal的版本冲突,在导入读取的时候获取不到值) package cn.iocoder.yudao.module.project.controller.admin.goods.vo;import com.alibaba.excel.annotation.ExcelI…...

关于线程池的执行流程和拒绝策略

使用线程池的好处为: 降低资源消耗:减少线程的创建和销毁带来的性能开销。 提高响应速度:当任务来时可以直接使用,不用等待线程创建 可管理性: 进行统一的分配,监控,避免大量的线程间因互相抢…...

XCTF-web-easyupload

试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

push [特殊字符] present

push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...