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

java集合 之 多列集合

目录

引言

一、Map接口概述

二、常见方法

1、put(K key,V value)

2、get(Object key)

3、remove(Object key)

4、containsKey(Object key)

5、containsValue(Object value)

6、size()

7、isEmpty()

9、keySet()

10、values()

11、entrySet()

三、迭代器 Iterator 

1、核心方法:

①hasNext()

②next()

③remove()

2、使用模式

3、不同集合的迭代器

① List 的迭代器

② Set 的迭代器

③ Map 的迭代器

④ ListIterator 的特殊功能

四、Map 的主要实现类

1、HashMap——对应HashSet

2、Hashtable——对应Vector

3、TreeMap——对应TreeSet

4、LinkedHashMap——对应LinkedHashSet


前面我们提到了单列集合:

Java集合 之 单列集合-CSDN博客https://blog.csdn.net/qq_73698057/article/details/150275046?spm=1001.2014.3001.5502

下面我们接着来看多列集合

引言

        想象一下

        1990年代初的Java开发团队正在设计一个图书馆管理系统

        他们需要一种数据结构来存储"书名-位置"这样的键值对关系

        如果使用List,每次查找都需要遍历整个列表

        如果使用Set,又只能存储单一值(去重)

        于是,他们创造了Map接口——一种革命性的双列集合

        就像图书馆的目录系统一样

        通过书名(键)快速找到书架位置(值)

        这个设计灵感来源于现实世界中的字典、电话簿、目录索引等

        它们都遵循"通过一个标识符查找相关信息"的模式

一、Map接口概述

Map 是一种双列集合,用于存储键值对(key - value)

特点:

        1. 存储元素时,必须以键值对的方式进行

        2. 键key:键是唯一的,每个键只能对应一个值

            值value:值可以重复,不同的键可以关联相同的值

        3. 查找:高效的,通过唯一的键值可以快速查到对应的value值

        4. 底层:哈希表或者红黑树等 实现的

好,废话不多说

Map的学习思路和前面单列集合差不多

我们直接来看它有什么方法

二、常见方法

1、put(K key,V value)

方法声明:

        V put(K key,V value)

        

解释:

泛型中常见的类型参数命名约定:

K - Key(键)

V - Value(值)

E - Element(元素)

T - Type(类型)

N - Number(数字)

        

在 Map 中,V 代表值的类型,示例:

import java.util.*;public class GenericTypeExample {public static void main(String[] args) {// Map<String, Integer> 中:// K = String(键的类型)// V = Integer(值的类型)Map<String, Integer> scoreMap = new HashMap<>();// put 方法:V = IntegerInteger oldValue = scoreMap.put("张三", 95); // V 作为参数和返回值类型// get 方法:V = IntegerInteger score = scoreMap.get("张三"); // V 作为返回值类型// remove 方法:V = IntegerInteger removedValue = scoreMap.remove("张三"); // V 作为返回值类型// values 方法:返回 Collection<V>,这里 V = IntegerCollection<Integer> scores = scoreMap.values(); // V 作为集合元素类型}
}

参数:

        key:要关联的键,不能为null(某些实例例外)

        value:与键关联的值,可以为null

返回值:

        返回被 覆盖 的值

        如果 key 之前没有映射(即对应的值),则返回null

        如果 key 已经存在,则返回被覆盖的之前的值

作用:

        将指定的 键值对 添加到 Map 中

        如果 键 已存在则替换旧值

是否改变原始值:

        

注意事项:

        键必须唯一,重复的键会覆盖原有值

        多个键可以映射到同一个值

import java.util.*;public class PutMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();// 第一次添加,返回nullInteger oldValue1 = map.put("Apple", 5);System.out.println("第一次添加Apple: " + oldValue1); // null// 再次添加相同键,返回旧值Integer oldValue2 = map.put("Apple", 10);System.out.println("第二次添加Apple: " + oldValue2); // 5System.out.println("当前Apple的值: " + map.get("Apple")); // 10}
}

2、get(Object key)

方法声明:

        V get(Object key)

参数:

        key:要 获取 的键

返回值:

        如果该键有映射的值,返回对应的值

        如果没有,返回null

作用:

        返回指定键所映射的 值 

是否改变原始值:

        

注意事项:

        返回 null 可能表示键不存在,也可能表示键映射到 null 值

        需要区分这两种情况的话,用 containsKey 方法(下面会提到)

import java.util.*;public class GetMethodExample {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put("name", "张三");map.put("nullValue", null); // 显式存储null值// 获取存在的键String name = map.get("name");System.out.println("name的值: " + name); // 张三// 获取不存在的键String notExist = map.get("age");System.out.println("不存在的键: " + notExist); // null// 获取显式存储为null的键String nullValue = map.get("nullValue");System.out.println("存储为null的值: " + nullValue); // null// 如何区分"键不存在"和"键映射到null"System.out.println("键是否存在: " + map.containsKey("age")); // falseSystem.out.println("键是否存在: " + map.containsKey("nullValue")); // true}
}

3、remove(Object key)

方法声明:

        V remove(Object key)

参数:

        key:要 移除 的键

返回值:

        如果该键有映射的值,返回被移除的 值 

        如果没有,则返回 null

作用:

        从 Map 中移除指定键的映射关系,即删除这个 键值对

是否改变原始值:

        

注意事项:

        返回值同样存在 null 歧义问题

import java.util.*;public class RemoveMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Apple", 5);map.put("Banana", 3);map.put("Orange", null); // 存储null值// 移除存在的键Integer removedValue = map.remove("Apple");System.out.println("移除的值: " + removedValue); // 5System.out.println("移除后Map大小: " + map.size()); // 2// 移除不存在的键Integer notExist = map.remove("Grape");System.out.println("移除不存在的键: " + notExist); // null// 移除存储为null的键Integer nullRemoved = map.remove("Orange");System.out.println("移除null值: " + nullRemoved); // nullSystem.out.println("移除后Map大小: " + map.size()); // 1}
}

4、containsKey(Object key)

方法声明:

        boolean containsKey(Object key)

参数:

        key:要 检查 的键

返回值:

        如果 Map 包含指定键的映射关系,返回 true

        否则返回 false

作用:

        检查 Map 是否包含指定键

是否改变原始值:

        

注意事项:

        时间复杂度O(1)

import java.util.*;public class ContainsKeyMethodExample {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put("name", "张三");map.put("address", null); // 显式存储null值// 检查存在的键System.out.println("包含name键: " + map.containsKey("name")); // true// 检查不存在的键System.out.println("包含age键: " + map.containsKey("age")); // false// 检查存储为null的键System.out.println("包含address键: " + map.containsKey("address")); // true// 正确处理get()返回null的情况String value = map.get("someKey");if (map.containsKey("someKey")) {System.out.println("键存在,值为: " + value);} else {System.out.println("键不存在");}}
}

5、containsValue(Object value)

方法声明:

        boolean containsValue(Object value)

参数:

        value:要 检查 的 值

返回值:

        如果 Map 将一个或多个键映射到指定值,返回 true

        否则返回 false

作用:

        检查 Map 是否包含指定值

是否改变原始值:

        

注意事项:

        需要遍历所有值,时间复杂度O(n)

        底层使用equals方法比较值

import java.util.*;public class ContainsValueMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Apple", 5);map.put("Banana", 3);map.put("Orange", 5); // 重复的值// 检查存在的值System.out.println("包含值5: " + map.containsValue(5)); // true// 检查不存在的值System.out.println("包含值10: " + map.containsValue(10)); // false// 多个键映射到同一个值System.out.println("值5出现次数: 多于1次");}
}

6、size()

方法声明:

        int size()

参数:

        无

返回值 作用:

        返回 Map 中键值对的数量

是否改变原始值:

        

注意事项:

       空 Map 的 size 为0

挺简单的懒得写了

7、isEmpty()

方法声明:

        boolean isEmpty()

参数:

        无

返回值:

        如果 Map不包含键值对,返回 true

        否则返回 false

作用:

        检查 Map 是否为空

是否改变原始值:

        

注意事项:

       等价于 size() == 0

8、clear()

方法声明:

        void clear()

参数:

        无

返回值:

        void

作用:

        移除 Map 中所有的键值对

是否改变原始值:

        

注意事项:

        执行后 Map 为空

        不会将 Map 引用设为 null

import java.util.*;public class ClearMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("A", 1);map.put("B", 2);map.put("C", 3);System.out.println("清除前大小: " + map.size()); // 3System.out.println("清除前是否为空: " + map.isEmpty()); // falsemap.clear();System.out.println("清除后大小: " + map.size()); // 0System.out.println("清除后是否为空: " + map.isEmpty()); // true// Map引用仍然有效,只是内容被清空map.put("D", 4);System.out.println("清空后重新添加: " + map.size()); // 1}
}

9、keySet()

方法声明:

        Set<K> keySet()

参数:

        无

返回值:

        Map 中所有键的 Set 视图

      (就是把 Map 里的所有键拿出来,放到 Set 里给你看)

作用:

        返回 Map 中所有键的集合

     

是否改变原始值:

        

注意事项:

        返回的 Set 与原来的 Map关联,修改会影响原来的 Map

        不能通过 keySet 添加元素

        可以通过 keySet 移除元素

        切记不是在遍历里修改,遍历里修改元素用 Iterator

        下面介绍完三个获取视图的方法再说这个问题

import java.util.*;public class KeySetMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Apple", 5);map.put("Banana", 3);map.put("Orange", 8);// 获取所有键Set<String> keys = map.keySet();System.out.println("所有键: " + keys); // [Apple, Banana, Orange]// 遍历所有键for (String key : keys) {System.out.println(key + " -> " + map.get(key));}// 通过keySet移除元素会影响原Mapkeys.remove("Apple");System.out.println("移除Apple后Map: " + map); // {Banana=3, Orange=8}// 不能通过keySet添加元素// keys.add("Grape"); // UnsupportedOperationException}
}

10、values()

方法声明:

        Collection<V> values()

参数:

        无

返回值:

        Map 中所有值的 Collection 视图

作用:

        返回 Map 中所有值的集合

     

是否改变原始值:

        

注意事项:

        返回的 Collection 与原来的 Map关联

        不能通过 values 添加或移除元素

        值可以重复

import java.util.*;public class ValuesMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Apple", 5);map.put("Banana", 3);map.put("Orange", 5); // 重复的值map.put("Grape", 3);   // 重复的值// 获取所有值Collection<Integer> values = map.values();System.out.println("所有值: " + values); // [5, 3, 5, 3]// 统计值的出现次数Map<Integer, Integer> countMap = new HashMap<>();for (Integer value : values) {countMap.put(value, countMap.getOrDefault(value, 0) + 1);}System.out.println("值的统计: " + countMap); // {3=2, 5=2}}
}

11、entrySet()

方法声明:

        Set<Map.Entry<K,V>> entrySet()

参数:

        无

返回值:

        Map 中所有键值对的 Set 视图

作用:

        返回 Map 中所有键值对的集合

     

是否改变原始值:

        

注意事项:

        Map.Entry 是键值对的表示

        可以通过 Entry 修改值

        是遍历 Map 最高效的方式

import java.util.*;public class EntrySetMethodExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Apple", 5);map.put("Banana", 3);map.put("Orange", 8);// 获取所有键值对Set<Map.Entry<String, Integer>> entries = map.entrySet();// 遍历键值对(最高效的方式)for (Map.Entry<String, Integer> entry : entries) {System.out.println(entry.getKey() + " -> " + entry.getValue());}// 通过Entry修改值for (Map.Entry<String, Integer> entry : entries) {if (entry.getKey().equals("Apple")) {entry.setValue(10); // 修改值}}System.out.println("修改后Map: " + map); // {Apple=10, Banana=3, Orange=8}}
}

好,我们来补充一下 Iterator

三、迭代器 Iterator 

主要是用来用统一的方式遍历不同类型的集合

是集合框架中的一种设计模式

可以想象成一个指针

它在集合的元素之间移动

逐个访问每个元素

1、核心方法:

①hasNext()

方法声明:

        boolean hasNext()

返回值:

        true:还有下一个元素

        false:已经到达集合末尾

作用:

        检查是否还有下一个元素

②next()

方法声明:

        E next()

返回值:

        集合中的下一个元素

作用:

        返回下一个元素,并将迭代器向前移动一位

③remove()

方法声明:

        void remove()

作用:

        删除上一次 next() 返回的元素

注意事项:

        必须在调用 next() 之后才能调用

        每次 next() 调用之后只能调用一次

        这是遍历过程中唯一安全的修改集合的方式

import java.util.*;public class RemoveExample {public static void main(String[] args) {List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));System.out.println("原始列表: " + list);Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String element = iterator.next();if ("B".equals(element) || "D".equals(element)) {iterator.remove(); // 安全删除}}System.out.println("删除后列表: " + list); // [A, C]}
}

2、使用模式

import java.util.*;public class BasicIteratorPattern {public static void main(String[] args) {Collection<String> collection = Arrays.asList("Apple", "Banana", "Orange");// 1. 获取迭代器Iterator<String> iterator = collection.iterator();// 2. 遍历元素的标准模式while (iterator.hasNext()) {String element = iterator.next();System.out.println(element);}}
}

3、不同集合的迭代器

回到之前的问题

keySet、values、entrySet这哥仨是可以调用迭代器在遍历里修改元素的

为什么可以呢?

注意看他们仨的方法声明

两个返回Set,而Set继承自Collection

一个返回Collection

而Collection 实现了Iterable接口

所以可以调用 Iterator

① List 的迭代器

import java.util.*;public class ListIteratorExample {public static void main(String[] args) {List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));// 普通 IteratorIterator<String> iterator = list.iterator();System.out.println("普通迭代器遍历:");while (iterator.hasNext()) {System.out.println(iterator.next());}// ListIterator(功能更强大)ListIterator<String> listIterator = list.listIterator();System.out.println("\nListIterator 正向遍历:");while (listIterator.hasNext()) {int index = listIterator.nextIndex();String element = listIterator.next();System.out.println("索引 " + index + ": " + element);}System.out.println("\nListIterator 反向遍历:");while (listIterator.hasPrevious()) {int index = listIterator.previousIndex();String element = listIterator.previous();System.out.println("索引 " + index + ": " + element);}}
}

② Set 的迭代器

import java.util.*;public class SetIteratorExample {public static void main(String[] args) {Set<String> set = new HashSet<>(Arrays.asList("Apple", "Banana", "Orange"));// Set 的迭代器(无序)Iterator<String> iterator = set.iterator();System.out.println("HashSet 元素:");while (iterator.hasNext()) {System.out.println(iterator.next());}}
}

③ Map

Map本身不可以使用迭代器,原因:

  1. Map接口没有实现Iterable接口
  2. Map是键值对的映射关系,不是线性集合结构
  3. 没有直接的iterator()方法

所以 Map 就用刚才那哥仨简介调用迭代器

import java.util.*;public class MapIteratorExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("Apple", 5);map.put("Banana", 3);map.put("Orange", 8);// Map 本身没有 Iterator,但可以通过视图获取System.out.println("通过 keySet 遍历:");Iterator<String> keyIterator = map.keySet().iterator();while (keyIterator.hasNext()) {String key = keyIterator.next();System.out.println(key + " -> " + map.get(key));}System.out.println("\n通过 entrySet 遍历:");Iterator<Map.Entry<String, Integer>> entryIterator = map.entrySet().iterator();while (entryIterator.hasNext()) {Map.Entry<String, Integer> entry = entryIterator.next();System.out.println(entry.getKey() + " -> " + entry.getValue());}}
}

④ ListIterator 的特殊功能

ListIterator 是 Iterator 的子接口,专门为 List 设计,提供更多功能:

import java.util.*;public class ListIteratorFeatures {public static void main(String[] args) {List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));System.out.println("原始列表: " + list);ListIterator<String> listIterator = list.listIterator();// 1. 正向遍历System.out.println("正向遍历:");while (listIterator.hasNext()) {int index = listIterator.nextIndex();String element = listIterator.next();System.out.println("索引 " + index + ": " + element);}// 2. 反向遍历System.out.println("\n反向遍历:");while (listIterator.hasPrevious()) {int index = listIterator.previousIndex();String element = listIterator.previous();System.out.println("索引 " + index + ": " + element);}// 3. 在当前位置添加元素listIterator.next(); // 移动到第一个元素listIterator.add("X"); // 在当前位置前添加System.out.println("\n添加X后: " + list); // [X, A, B, C]// 4. 设置当前元素listIterator.next(); // 移动到AlistIterator.set("Y"); // 替换A为YSystem.out.println("替换后: " + list); // [X, Y, B, C]}
}

四、Map 的主要实现类

1、HashMap——对应HashSet

底层:

        哈希表

特点:

        无序

        存储顺序不保证一致

        键唯一,所以key的自定义类要注意hashCode和equals方法的重写

        值可以重复

        线程不安全

        null:

                key 可以为null,只能有一个

                value 可以为null,可以有多个

注意:

        HashMap在添加值的时候先调用hashCode方法,再调用equals方法
        HashSet底层用到了HashMap

import java.util.*;public class HashMapExample {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();// HashMap允许null键和null值map.put(null, 1); // null键map.put("nullValue", null); // null值map.put(null, 2); // 覆盖null键的值System.out.println("HashMap: " + map);System.out.println("null键的值: " + map.get(null)); // 2}
}

2、Hashtable——对应Vector

底层:

        哈希表

特点:

        存储顺序不保证一致

        键唯一,所以key的自定义类要注意hashCode和equals方法的重写

        值可以重复

        线程安全

        null:

                key 和 value 都不能为null

import java.util.*;public class HashtableExample {public static void main(String[] args) {Map<String, Integer> map = new Hashtable<>();map.put("Apple", 1);map.put("Banana", 2);// Hashtable不允许null键和null值// map.put(null, 1); // NullPointerException// map.put("nullValue", null); // NullPointerExceptionSystem.out.println("Hashtable: " + map);}
}

3、TreeMap——对应TreeSet

底层:

        红黑树

        实现了 SortedMap 接口,所以元素的顺序会自动排序

特点:

        有序

        对key值排序,自然排序和比较器排序(就近原则:比较器排序 > 自然排序)

        键唯一,所以key的自定义类要注意hashCode和equals方法的重写

        值可以重复

        线程不安全,可以通过其他方式解决线程安全问题

        null:

                key 不能为null,会抛出空指针异常

                value 可以为null,可以有多个

import java.util.*;public class TreeMapExample {public static void main(String[] args) {Map<String, Integer> map = new TreeMap<>();map.put("Banana", 2);map.put("Apple", 1);map.put("Cherry", 3);// 自动按键排序System.out.println("TreeMap: " + map); // {Apple=1, Banana=2, Cherry=3}}
}

4、LinkedHashMap——对应LinkedHashSet

底层:

       哈希表 和 双向链表

特点:

        按照存入顺序排序

        键唯一,所以key的自定义类要注意hashCode和equals方法的重写

        值可以重复

        线程不安全,可以通过其他方式解决线程安全问题

        null:

                key 能为null,只能有一个

                value 可以为null,可以有多个

import java.util.*;public class LinkedHashMapExample {public static void main(String[] args) {Map<String, Integer> map = new LinkedHashMap<>();map.put("First", 1);map.put("Second", 2);map.put("Third", 3);// 保持插入顺序System.out.println("LinkedHashMap: " + map); // {First=1, Second=2, Third=3}// 访问不会改变顺序map.get("Second");System.out.println("访问后: " + map); // 顺序不变}
}

http://www.dtcms.com/a/330594.html

相关文章:

  • Python/Node.js 调用taobao API:构建实时商品详情数据采集服务
  • 使用HalconDotNet实现异步多相机采集与实时处理
  • Mybatis学习笔记(六)
  • 桥接模式C++
  • 成都国际影像产业园:接重庆五一职院实训就业考察
  • [系统架构设计师]软件工程基础知识(五)
  • 系统思考:转型困扰与突破
  • 【软考中级网络工程师】知识点之入侵检测深度剖析
  • 开源安全云盘存储:Hoodik 实现端到端数据加密,Docker快速搭建
  • 分享一个基于Hadoop+spark的超市销售数据分析与可视化系统,超市顾客消费行为分析系统的设计与实现
  • Java应用架构实战指南:主流模式解析与Spring落地实践
  • 从零开始学Python之数据结构(字符串以及数字)
  • Java 大视界 -- Java 大数据机器学习模型在金融欺诈检测与防范策略制定中的应用(397)
  • 工业一体机5G通讯IC/ID刷卡让MES系统管理更智能
  • 第四天~在CANFD或CAN2.0的ARXML文件中实现Multiplexor多路复用信号实战
  • 怎么判断晶振的好坏,有什么简单的办法
  • AR技术赋能电力巡检:智能化升级的“秘密武器”
  • 计算机视觉(opencv)实战三——图像运算、cv2.add()、cv2.addWeighted()
  • 设计模式笔记_行为型_责任链模式
  • 【论文阅读 | CVPR 2024 | UniRGB-IR:通过适配器调优实现可见光-红外语义任务的统一框架】
  • linux 内核 - 内存管理的层次化结构
  • UE5配置MRQ编解码器输出MP4视频
  • Linux网络编程:应用层自定义协议与序列化
  • 《量子雷达》第5章 量子雷达发射机 预习2025.8.14
  • 人工智能——卷积神经网络自定义模型全流程初识
  • .NET 的 WebApi 项目必要可配置项都有哪些?
  • CPUcores-【硬核优化】CPU增强解锁全部内核!可优化游戏性能、提升帧数!启用CPU全内核+超线程,以更高优先级运行游戏!支持各种游戏和应用优化~
  • Mybatis学习笔记(四)
  • 【论文阅读】基于卷积神经网络和预提取特征的肌电信号分类
  • CSS isolation属性