java基础——java集合map详解

目录

一、引言

二、Map接口概述

1.常用方法

2.实现Map的主要类

2.1.HashMap

2.2.LinkedHashMap

2.3.Hashtable(遗留类,已过时)

2.4.TreeMap

2.5.ConcurrentHashMap

3.总结对比

4.不常用的实现类

4.1.IdentityHashMap

4.2.WeakHashMap

4.3.EnumMap

4.4.ConcurrentSkipListMap

5.了解SynchronizedMap

三、Map的遍历与去重

 1.Map 的四种主要遍历方式

 1.1.使用entrySet()遍历键值对

 1.2.使用keySet()遍历键

 1.3.使用values()遍历值

1.4.使用Java 8的forEach方法

2.Map去重方法

四、结语


一、引言

在Java编程中,Map接口是处理键值对数据的核心工具之一。它广泛应用于缓存、配置管理、数据映射等场景。无论是初学者还是有一两年开发经验的程序员,掌握Map接口及其常用实现类的使用都是非常重要的。
本文将详细解析Java中的Map接口,包括其基本概念、常用方法、主要实现类、遍历方式以及不同实现类的适用场景和注意事项。通过实际代码示例,帮助读者更好地理解和应用Map。

以下是一个展示Java中常用Map集合的思维导图:

java基础——java集合map详解_第1张图片

二、Map接口概述

Map接口是Java集合框架中的一部分,用于存储键值对(key-value pairs)。与List和Set不同,Map不继承自Collection接口,而是独立存在。Map中的每个元素都是一个键值对,其中键(key)是唯一的,而值(value)可以重复。Map接口允许通过键来快速查找、插入和删除对应的值。键的唯一性确保了每个键只能映射到一个值,但不同的键可以映射到相同的值。

1.常用方法

put(K key, V value):将键值对放入Map。
get(Object key):根据键获取对应的值。
remove(Object key):根据键删除键值对。
containsKey(Object key):判断是否包含指定的键。
containsValue(Object value):判断是否包含指定的值。
size():返回Map中键值对的数量。
isEmpty():判断Map是否为空。
keySet():返回所有键的集合。
values():返回所有值的集合。
entrySet():返回所有键值对的集合。

 // 创建一个HashMap实例
        Map map = new HashMap<>();

        // put方法:添加键值对
        map.put("apple", 3);
        map.put("banana", 5);

        // get方法:获取键对应的值
        System.out.println("apple的数量: " + map.get("apple"));  // 输出:3

        // containsKey方法:检查是否包含某个键
        System.out.println("是否包含键'banana': " + map.containsKey("banana"));  // 输出:true

        // remove方法:删除键值对
        map.remove("banana");

        // size方法:获取Map的大小
        System.out.println("当前Map的大小: " + map.size());  // 输出:1

        // isEmpty方法:检查Map是否为空
        System.out.println("Map是否为空: " + map.isEmpty());  // 输出:false
2.实现Map的主要类
2.1.HashMap

HashMap 是基于哈希表实现的,允许存储键值对,键和值都可以为 null。它不保证元素的顺序,且是非线程安全的。
特点:
查找、插入和删除速度快。

支持null键和null值 ,无序存储。

非线程安全。
使用场景:

适用于需要快速查找、插入和删除的场景,且不关心元素的顺序。

示例代码:

    Map map = new HashMap<>();
    map.put("apple", 3);
    map.put("banana", 5);

    System.out.println("apple的数量: " + map.get("apple")); // 输出:3
    System.out.println("是否包含banana: " + map.containsKey("banana")); // 输出:true
   
2.2.LinkedHashMap

LinkedHashMap继承自HashMap是另一个重要的List实现,它基于双向链表实现,对于插入和删除操作具有较高的性能,但对于随机访问效率较低。
特点:
支持高效的插入和删除操作 ,保持插入和访问顺序。
非线程安全。
可以作为堆栈、队列或双端队列使用。
使用场景:
适用于需要保持插入顺序或访问顺序的场景。

示例代码:

 Map map = new LinkedHashMap<>();
 map.put("apple", 3);
 map.put("banana", 5);

 for (Map.Entry entry : map.entrySet()) {
      System.out.println(entry.getKey() + ": " + entry.getValue());
 }
        // 输出顺序与插入顺序一致
2.3.Hashtable(遗留类,已过时)

早期的线程安全 Map 实现,它通过同步方法来实现线程安全。

特点:

线程安全,但性能较低。

所有方法都使用synchronized修饰。

不允许null键和null值。

使用场景:

适用于需要线程安全的场景,但性能不如 ConcurrentHashMap。

示例代码:

 Map map = new Hashtable<>();
 map.put("apple", 3);
 map.put("banana", 5);

 System.out.println("apple的数量: " + map.get("apple")); // 输出:3
    
2.4.TreeMap

TreeMap 是基于红黑树实现的,它保持键的自然顺序或自定义顺序

特点:

按照键的自然顺序或自定义顺序排序。

不允许null键,但允许null值。

查找、插入和删除速度快。

非线程安全。

使用场景:

适用于需要按键排序的场景。

示例代码:

 Map map = new TreeMap<>();
 map.put("banana", 5);
 map.put("apple", 3);

 for (Map.Entry entry : map.entrySet()) {
     System.out.println(entry.getKey() + ": " + entry.getValue());
 }
        // 输出按键的字母顺序排列
2.5.ConcurrentHashMap

ConcurrentHashMap 是线程安全的 HashMap 实现。

版本演变:

JDK 1.7 及之前使用分段锁(Segment)机制,多个锁控制不同 Segment,降低锁粒度。

JDK 1.8 及以后采用 CAS + synchronized + 红黑树 的机制,基于Node数组+链表+红黑树,每个桶自己加锁。

特点:

不允许null键和null值。

线程安全且性能高,支持高并发访问。

使用场景:

适用于需要在多线程环境中高效地进行并发操作。

适用于需要线程安全且高性能的Map。

示例代码:

    public static void main(String[] args) throws InterruptedException {
        Map map = new ConcurrentHashMap<>();

        Runnable putTask = () -> {
            for (int i = 0; i < 1000; i++) {
                map.put(i, "value" + i);
            }
        };

        Runnable getTask = () -> {
            for (int i = 0; i < 1000; i++) {
                map.get(i);
            }
        };

        Thread t1 = new Thread(putTask);
        Thread t2 = new Thread(getTask);
        Thread t3 = new Thread(putTask);

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

        System.out.println("Map大小: " + map.size()); // 输出:1000(最终唯一)
    
3.总结对比

java基础——java集合map详解_第2张图片

4.不常用的实现类

4.1.IdentityHashMap

特点:基于引用地址判断键是否相等。

使用场景:适用于需要精确对象比较的场景。

4.2.WeakHashMap

特点:键为弱引用,易被GC回收。

使用场景:适合做缓存或临时映射。

4.3.EnumMap

特点:键必须是 枚举类型(enum),不允许 null 键,但允许 null 值。

使用场景:枚举作为键的映射关系管理。

4.4.ConcurrentSkipListMap

特点:基于跳表(SkipList)实现的有序并发 Map,支持范围查询,支持高并发读写操作。

使用场景:适用于多线程下需排序的场景。

5.了解SynchronizedMap

它不是独立的 Map 实现类,而是通过 Collections 工具类将普通 Map 包装成线程安全的 Map。

特点:

线程安全:通过在每个方法上加锁(synchronized)实现同步。

非并发专用:适用于并发量不高的场景,性能不如 ConcurrentHashMap。

可包装任意 Map 实现:可以包装 HashMap、TreeMap 等任何实现了 Map 接口的类。

锁粒度大:每次操作都会锁定整个 Map,高并发下容易成为瓶颈。

使用场景:

单线程或低并发环境下的线程安全需求。

不希望引入额外依赖时使用标准库提供的工具。

快速将已有 Map 变为线程安全,但不要求高性能。

示例代码:

        // 创建一个普通HashMap
        Map map = new HashMap<>();

        // 转换为线程安全的Map
        Map synchronizedMap = Collections.synchronizedMap(map);

        // 多线程环境下使用该map是线程安全的
        synchronizedMap.put("key", "value");
        System.out.println(synchronizedMap.get("key"));

三、Map的遍历与去重

 1.Map 的四种主要遍历方式
 1.1.使用entrySet()遍历键值对
        Map map = new HashMap<>();
        map.put("apple", 3);
        map.put("banana", 5);

        // 使用entrySet遍历键值对
        for (Map.Entry entry : map.entrySet()) {
            System.out.println("键: " + entry.getKey() + ", 值: " + entry.getValue());
        }
 1.2.使用keySet()遍历键
        Map map = new HashMap<>();
        map.put("apple", 3);
        map.put("banana", 5);

        // 使用keySet遍历键
        for (String key : map.keySet()) {
            System.out.println("键: " + key + ", 值: " + map.get(key));
        }
 1.3.使用values()遍历值
        Map map = new HashMap<>();
        map.put("apple", 3);
        map.put("banana", 5);

        // 使用values遍历值
        for (Integer value : map.values()) {
            System.out.println("值: " + value);
        }
1.4.使用Java 8的forEach方法
        Map map = new HashMap<>();
        map.put("apple", 3);
        map.put("banana", 5);

        // 使用Java 8的forEach遍历
        map.forEach((key, value) -> System.out.println("键: " + key + ", 值: " + value));
    
2.Map去重方法

键自动唯一,不会重复存储。键重复了新值会覆盖旧值。

示例代码:

        Map map = new HashMap<>();

        map.put("apple", 1);
        map.put("apple", 2); // 重复的 key,会被覆盖

        System.out.println(map); // 输出:{apple=2}

四、结语

Map是Java中非常重要的集合类型,理解其核心概念、常用方法以及不同实现类的特点对于编写高效的Java程序至关重要。本文从基础到进阶,详细介绍了Map接口的常用方法、遍历方式以及各个实现类的使用场景和注意事项。希望本文能够帮助初学者和有一定开发经验的程序员更好地掌握Map的使用,提升编程能力

你可能感兴趣的:(学习java,开发语言,java)