news 2026/7/7 5:14:34

Java Map 集合学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Map 集合学习笔记

Map 概述

Map 和 Collection 没有继承关系。
Map 以键值对的方式存储数据,key 和 value 都是存储对象的内存地址。
key 起到主导作用,value 是 key 的一个附属品,所有的 key 是一个 Set 集合。

Map 接口常用方法

  • void clear()
  • boolean containsKey(Object key)
  • boolean containsValue(Object value)
  • boolean isEmpty()
  • V get(Object key)通过 key 获取 value
  • Set<K> keySet()获取 Map 集合所有的 key
  • V put(K key, V value)向 Map 集合中添加键值对
  • V remove(Object key)通过 key 删除键值对
  • int size()获取集合中键值对个数
  • Collection<V> values()获取 Map 集合中所有 value,返回一个 Collection
  • Set<Map.Entry<K,V>> entrySet()将 Map 集合转换成 Set 集合。转换后 key 和 value 对应起来,形成 key = 对应 value 的形式。
    Entry 是 Map 的静态内部类。
Map<Integer,String>map=newHashMap<>();Set<Map.Entry<Integer,String>>set=map.entrySet();// set 元素类型就是 Map.Entry<K,V>

遍历 Map 集合

第一种方式

  1. 通过keySet()方法获取所有的 key,所有的 key 是一个 Set 集合。
  2. 遍历 key(可以使用迭代器或者 foreach),通过 key 获取 value(通过get方法)。

第二种方式

  1. 通过entrySet()方法将 Map 全部转换成 Set。
  2. 通过迭代器或者 foreach 遍历 Set 集合。
Set<Map.Entry<Integer,String>>set=map.entrySet();Iterator<Map.Entry<Integer,String>>it=set.iterator();while(it.hasNext()){Map.Entry<Integer,String>node=it.next();Integerkey=node.getKey();Stringvalue=node.getValue();}for(Map.Entry<Integer,String>node:set){Integerkey=node.getKey();Stringvalue=node.getValue();}

HashMap 集合

底层数据结构

  1. HashMap 集合底层是哈希表的数据结构。
  2. 哈希表是数组和单向链表的结合体(一维数组,数组中每一个元素是一个单链表),能充分发挥数组和单向链表的优点。

底层源码

publicclassHashMap{Node<K,V>table;staticclassNode{finalinthash;// 哈希值(是 key 的 hashCode() 方法的执行结果,通过哈希算法计算出数组下标)finalKkey;finalVvalue;Node<K,V>next;// 下一个节点的存储地址}}

深入 put(k,v) 方法

实现原理:

  1. 先将 k,v 封装到 Node 对象中。
  2. 底层调用hashCode()方法得出 hash 值,通过哈希算法将 hash 值转换成数组下标。
    • 下标位置没有元素的话,将 Node 添加到这个位置。
    • 如果对应下标有链表,就拿着 k 和链表中每一个 k 进行equals比较,如果都返回 false 则添加到链表末尾;如果有返回 true 的,那么这个节点的 value 被覆盖。

深入 get(k) 方法

原理类似 put(k,v):
调用 key 的hashCode()方法得出 hash 值,然后通过哈希算法得出数组下标。

  • 如果该下标下没有元素则返回 null。
  • 否则拿着 k 和该下标的链表进行equals比较,有返回 true 的就返回 value,没有的话就返回 null。

重写 hashCode() 和 equals()

HashMap 集合中的hashCode()equals()方法会被调用,所以需要对这两个方法进行重写。
由于放在 HashMap 中的 key 部分就是放在 HashSet 集合中了,所以 HashSet 集合也需要重写hashCode()equals()

hashCode使用不当会导致 HashMap 无法发挥性能:

  • 如果hashCode的返回值都不一样,HashMap 就会被用成一维数组。
  • 如果返回值都一样,就会被用成单向链表。
    要想充分发挥 HashMap 的性能,这些元素最好散列分布均匀。

放在 HashMap 和 HashSet 中的元素都需要重写hashCodeequals方法。

扩容与红黑树优化

  • HashMap 中的所用容量占总容量 0.75 的时候就会开始扩容。
  • 在 JDK 8 之后,如果 HashMap 中单向链表的元素超过 8 个,单向链表的数据结构就会变成红黑树;而元素个数低于 6 时会将红黑树再改回单向链表。这样做可以提高检索效率。

HashMap 和 Hashtable 的区别

  • HashMap 允许 key 和 value 部分为 null,但只能有一个 key 为 null。
  • Hashtable 不允许 key 部分和 value 部分为空,会报空指针异常。
    由于 Hashtable 是线程安全的,其下方法都带synchronized关键字,效率低,所以不常用。

Properties 属性类

Properties 是一个 Map 集合,继承 Hashtable,Properties 的 key 和 value 都是 String 类型。
Properties 被称为属性类对象,是线程安全的。

  • 存:setProperty
  • 取:getProperty
Propertiespro=newProperties();pro.setProperty("111","abandon");pro.getProperty("111");

HashSet 集合

  • 无序不可重复。
Sets1=newHashSet();

TreeSet 集合

底层实现

TreeSet 集合底层实际是一个 TreeMap,TreeMap 集合底层是一个二叉树。
放到 TreeSet 集合中的元素,等同于放到 TreeMap 集合 key 部分了。
TreeMap 集合中的元素无序不可重复,但会自动排序。
但是对于自定义类型的元素来说,TreeSet 不能排序,因为没有指定比较规则,会抛出异常。

自平衡二叉树

  • 左小右大的方式存放。
  • 遍历二叉树的方式:
    • 前序遍历:根左右
    • 中序遍历:左根右
    • 后序遍历:左右根
  • TreeSet 和 TreeMap 采用中序遍历,Iterator 也是中序遍历。

元素排序的两种方式

放到 TreeSet 或者 TreeMap 集合 key 部分的元素要想做到排序有两种方式:

  1. 实现Comparable接口
  2. 在构造集合的时候传递一个比较器Comparator
第一种方式:实现 Comparable 接口

要进行比较就要让自定义类型实现Comparable接口,同时实现接口中的compareTo方法。
TreeSet 中的equals可以不重写,需要在这个方法中写出比较的规则。

compareTo源代码:

publicintcompareTo(To){return0;}

例如,有一个 Stu 类,需要根据年龄大小进行排序放到 TreeSet:

classStuimplementsComparable<Stu>{intage;publicStu(){}publicStu(intage){this.age=age;}publicintcompareTo(Stus){// 调用的时候就是 s1.compareTo(s),也就是 this(已放置的) 和 s(需要放置的) 比较returns.age-this.age;// 需要放置的 s 大返回正数,s 小返回负数,相等返回 0,然后调用者再根据返回值进行排序}}
第二种方式:使用比较器 Comparator

实现比较器接口:

classStu{intage;publicStu(){}publicStu(intage){this.age=age;}}classStuComparatorimplementsComparator<Stu>{publicintcompare(Stus1,Stus2){returns1.age-s2.age;}}// TreeSet<Stu> stus = new TreeSet<>(); 这个时候不能这么构造了TreeSet<Stu>stus=newTreeSet<>(newStuComparator());// 需要传递比较器进去

或者使用匿名内部类,直接 new 接口:

TreeSet<Stu>stus=newTreeSet<>(newComparator<Stu>(){publicintcompare(Stus1,Stus2){returns1.age-s2.age;}});

两种方式的选择

  • 当比较规则单一的时候,建议使用 Comparable 接口。
  • 如果有多个规则并需要频繁切换,建议使用 Comparator 接口。

集合工具类 Collections

java.util.Collections是集合工具类,注意与java.util.Collection(集合接口)区分。

Listl1=newArrayList();// 变成线程安全的Collections.synchronizedList(l1);// 此时 l1 就是线程安全的了l1.add(100);l1.add(200);// 排序Collections.sort(l1);// 对自定义类型的元素排序,例如 StuList<Stu>l2=newArrayList<>();// 两种方式:// 1. 实现 Comparable 接口// 2. 用比较器对象// Set 集合如何排序?可以将 Set 转换为 ListSet<Stu>set=newHashSet<>();List<Stu>list=newArrayList<>(set);Collections.sort(list);// 或者用比较器对象:Collections.sort(比较器对象)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 5:10:19

面包板 300mil 间距转接方案:3种自制DIP插针实测与成本对比

面包板300mil间距转接方案&#xff1a;3种自制DIP插针实测与成本对比在电子原型开发中&#xff0c;面包板因其无需焊接即可快速搭建电路的便利性&#xff0c;成为硬件创客和学生群体的必备工具。然而&#xff0c;当我们需要将双列直插&#xff08;DIP&#xff09;封装的模块连接…

作者头像 李华
网站建设 2026/7/7 5:09:05

微服务网关选型与落地:Kong、APISIX 与 Traefik 的工程实践对比

微服务网关选型与落地&#xff1a;Kong、APISIX 与 Traefik 的工程实践对比 一、网关不是「流量转发器」&#xff0c;而是「服务治理的第一道防线」 很多团队在引入微服务网关时&#xff0c;对它的期望是「把请求转发到正确的服务」——这没错&#xff0c;但远远不是全部。生产…

作者头像 李华
网站建设 2026/7/7 5:06:07

搜索matlab .m 文件中包含某些字符的.m 文件

%%% 使用系统命令 system(findstr /S /M min *.m); system(findstr /S /M max *.m); system(findstr /S /M std *.m); system(findstr /S /M mean *.m);% 一次性查找多个 system(findstr /S /M "min\|max\|std\|mean" *.m);

作者头像 李华
网站建设 2026/7/7 4:58:13

短示例驱动的仿生运动风格迁移方法

1. 项目概述&#xff1a;当生物运动规律遇上AI动作生成“短示例驱动的仿生运动风格迁移方法”——这名字听起来像实验室黑板上刚写下的公式&#xff0c;但其实它正悄悄改变动画制作、机器人控制甚至康复训练的底层逻辑。我第一次在客户现场看到这个技术落地时&#xff0c;是在一…

作者头像 李华
网站建设 2026/7/7 4:55:14

智能车越野组竞赛技术全解析:从传感器融合到控制算法

&#x1f680; 30款热门AI模型一站整合&#xff0c;DeepSeek/GLM/Qwen 随心用&#xff0c;限时 5 折。 &#x1f449; 点击领海量免费额度 这次我们来看智能车越野组竞赛的技术要点梳理。这个主题主要面向参加全国大学生智能汽车竞赛的选手&#xff0c;特别是选择越野组别的…

作者头像 李华