java.util.Map



java.util.Map

1.Map简介:

Map是Java中一个非常重要的数据结构,它以键值对(Key-Value)的形式存储数据。Map是一个接口,提供了一种映射关系,使得我们可以通过键(Key)找到对应的值(Value)。Map接口位于java.util包中。

1.1 键值对存储结构

Map中的元素以键值对的形式存在。键(Key)在Map中是唯一的,而值(Value)可以重复。键值对之间没有顺序关系。这种结构可以方便地实现查找、添加、删除等操作。

1.2. 基于接口编程

Map是一个接口,实际使用时,我们通常会使用它的实现类,如HashMap、TreeMap等。这符合基于接口编程的原则,可以根据实际需求灵活替换具体实现。

1.3. 不允许重复键

Map中的键必须唯一。如果尝试将一个已存在的键与新的值关联,那么原有的值将被替换。这是因为键在Map中具有唯一性,它可以唯一确定一个值。这种特性使得Map在查找数据时能够快速定位。

2.常用方法

Map接口定义了一些用于操作键值对的方法。以下是一些常用的方法:

public class MapExample {
    public static void main(String[] args) {
        // 创建一个HashMap实例
        Map<String, Integer> map = new HashMap<>();
2.1. put(key, value)

此方法用于将指定的键值对添加到Map中。如果Map中已经存在相同的键,则旧值将被替换为新值。返回值为替换前的旧值,如果不存在,则返回null。

// 添加键值对
map.put("Apple", 5);
map.put("Banana", 8);
map.put("Orange", 3);
2.2. get(key)

此方法用于通过指定的键检索相应的值。如果Map中不存在指定的键,则返回null。

// 获取值
int appleCount = map.get("Apple");
System.out.println("Apple count: " + appleCount); // 输出:Apple count: 5

2.3. remove(key)

此方法用于从Map中移除指定键的键值对。返回值为移除的键对应的值,如果不存在,则返回null。

  // 移除键值对
  map.remove("Banana");

2.4. containsKey(key)

此方法用于判断Map中是否存在指定的键。返回值为布尔类型,如果存在,则返回true,否则返回false。

 // 判断键是否存在
boolean hasApple = map.containsKey("Apple");
System.out.println("Has Apple: " + hasApple); // 输出:Has Apple: true
2.5. containsValue(value)

此方法用于判断Map中是否存在指定的值。返回值为布尔类型,如果存在,则返回true,否则返回false。

// 判断键是否存在
boolean hasValue3 = map.containsValue(3);
System.out.println("Has value 3: " + hasValue3); // 输出:Has value 3: true
2.6. keySet()

此方法用于获取Map中所有键的集合。返回值为Set类型,包含Map中所有的键。

// 判断值是否存在
Set<String> keys = map.keySet();
System.out.println("Keys: " + keys); // 输出:Keys: [Apple, Orange]
2.7. values()

此方法用于获取Map中所有值的集合。返回值为Collection类型,包含Map中所有的值。

// 获取键集合
Collection<Integer> values = map.values();
System.out.println("Values: " + values); // 输出:Values: [5, 3]
2.8. entrySet()

此方法用于获取Map中所有键值对的集合。返回值为Set类型,包含Map中所有的键值对(Map.Entry类型)。

// 获取键值对集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
2.9. clear()

此方法用于清除Map中所有的键值对。

// 清空Map
map.clear();
2.10. size()

此方法用于获取Map中键值对的数量。返回值为整数类型,表示Map中键值对的数量。

// 获取Map大小
int size = map.size();
System.out.println("Map size: " + size); // 输出:Map size: 0

以上是Java中Map接口的一些常用方法。在实际开发中,这些方法能帮助我们方便地操作Map中的数据。

3.Map的实现类

Java中的Map接口有多个实现类,具有不同的性能特点和使用场景。以下是一些常见的实现类:

3.1. HashMap

HashMap是基于哈希表的实现。它允许空键和空值,非同步,且不保证有序。HashMap提供了O(1)的查询、插入和删除操作。这是在很多场景下最常用的Map实现类。

  • 基于哈希表实现,数据存储在哈希表中。
  • 键值对无序,不保证任何特定的遍历顺序。
  • 允许空键(null key)和空值(null value)。
  • 非同步,不适用于多线程环境下的并发操作,如果需要线程安全,可以使用ConcurrentHashMap或使用Collections.synchronizedMap()将HashMap包装为同步的。
  • 插入、查询和删除操作的时间复杂度为O(1),在实际应用中具有很高的性能。
  • 适用于一般场景,特别是对键值对的顺序没有要求的情况。
3.2. LinkedHashMap

LinkedHashMap是基于哈希表和双向链表实现的。它允许空键和空值,非同步,且按照插入顺序或访问顺序进行排序。性能上接近于HashMap,但提供了顺序访问功能。适用于需要保持插入顺序或访问顺序的场景。

  • 基于哈希表和双向链表实现,数据存储在哈希表中,同时维护一个双向链表来记录键值对的顺序。
  • 键值对有序,可以按照插入顺序或访问顺序进行排序。
  • 允许空键(null key)和空值(null value)。
  • 非同步,如果需要线程安全,可以使用Collections.synchronizedMap()将LinkedHashMap包装为同步的。
  • 插入、查询和删除操作的时间复杂度为O(1),性能上接近于HashMap。
  • 适用于需要保持插入顺序或访问顺序的场景,如实现一个简单的LRU(最近最少使用)缓存。
3.3. TreeMap

TreeMap是基于红黑树实现的。它不允许空键,允许空值,非同步,且根据键的自然顺序或自定义比较器进行排序。提供了O(log n)的查询、插入和删除操作。适用于需要对键进行排序的场景。

  • 基于红黑树实现,数据存储在红黑树中。
  • 键值对有序,根据键的自然顺序或自定义比较器进行排序。
  • 不允许空键(null key),但允许空值(null value)。
  • 非同步,如果需要线程安全,可以使用Collections.synchronizedSortedMap()将TreeMap包装为同步的。
  • 插入、查询和删除操作的时间复杂度为O(log n),相对于HashMap和LinkedHashMap略慢。
  • 适用于需要对键进行排序的场景,如实现一个有序的键值对列表。
3.4. Hashtable

Hashtable是基于哈希表实现的。它不允许空键和空值,同步,且不保证有序。在多线程环境下性能较低,现已被ConcurrentHashMap取代。

3.5. ConcurrentHashMap

ConcurrentHashMap是基于分段锁技术的哈希表实现。它不允许空键和空值,同步,且不保证有序。为多线程环境提供了较好的性能。适用于需要线程安全的场景。

3.6. EnumMap

EnumMap是特殊的Map实现,要求键为枚举类型。内部使用数组实现,非同步,且按照枚举值的自然顺序排序。适用于键为枚举类型的场景。

3.7. WeakHashMap

WeakHashMap是基于哈希表实现的。它允许空键和空值,非同步,且不保证有序。与HashMap的区别在于,它的键是弱引用类型,当没有强引用指向键对象时,键值对可能被垃圾回收器回收。适用于需要自动回收不再使用的键值对的场景。

4.Map遍历方式

Java中可以使用多种方法遍历Map,以下是一些常见的遍历方式:

4.1. 遍历键(Key)

4.2. 遍历值(Value)

4.3. 遍历键值对(Key-Value)

public class MapTraversalExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("Apple", 5);
        map.put("Banana", 8);
        map.put("Orange", 3);

        // 4.1. 遍历键(Key)
        for (String key : map.keySet()) {
            System.out.println("Key: " + key);
        }

        // 4.2. 遍历值(Value)
        for (Integer value : map.values()) {
            System.out.println("Value: " + value);
        }

        // 4.3. 遍历键值对(Key-Value)
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
    }
}

5.HashMap、TreeMap和LinkedHashMap

1.底层数据结构:

  • HashMap:基于哈希表实现,使用数组+链表/红黑树的结构来存储键值对。

  • TreeMap:基于红黑树实现,是一个有序的字典数据结构。

  • LinkedHashMap:继承自HashMap,但在内部维护了一个双向链表,保证了元素的插入顺序。

2.排序:

  • HashMap:不保证元素的顺序,键值对在哈希表中的存储是无序的。

  • TreeMap:元素有序,根据键的自然顺序或者使用一个定制的Comparator进行排序。

  • LinkedHashMap:元素按照插入顺序排序,也可以通过访问顺序排序(需要在构造函数中指定)。

3.查询、插入、删除操作的时间复杂度:

  • HashMap:平均情况下,查询、插入、删除操作的时间复杂度均为O(1);在最坏情况下,时间复杂度为O(n)。

  • TreeMap:查询、插入、删除操作的时间复杂度均为O(log n)。

  • LinkedHashMap:查询、插入、删除操作的时间复杂度与HashMap相同。

4.线程安全性:

  • HashMap、TreeMap、LinkedHashMap都不是线程安全的。如果需要线程安全的Map实现,可以使用Collections.synchronizedMap()方法或者使用ConcurrentHashMap。

5.允许null键和值:

  • HashMap:允许一个null键和多个null值。

  • TreeMap:不允许null键,但允许多个null值。因为使用红黑树进行排序,null键无法进行比较排序。

  • LinkedHashMap:允许一个null键和多个null值,与HashMap一致。

4.线程安全性:

  • HashMap、TreeMap、LinkedHashMap都不是线程安全的。如果需要线程安全的Map实现,可以使用Collections.synchronizedMap()方法或者使用ConcurrentHashMap。

5.允许null键和值:

  • HashMap:允许一个null键和多个null值。

  • TreeMap:不允许null键,但允许多个null值。因为使用红黑树进行排序,null键无法进行比较排序。

  • LinkedHashMap:允许一个null键和多个null值,与HashMap一致。

根据上述比较,可以根据具体的应用场景来选择合适的Map实现。如果需要高效的查找、插入、删除操作,并且不关心元素的顺序,可以选择HashMap。如果需要有序的元素存储以及范围查询等功能,可以选择TreeMap。如果需要按照元素的插入顺序或者访问顺序进行排序,可以选择LinkedHashMap。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值