7.6 Map接口

7.6 Map接口

7.6.1 Map接口简介

定义和基本概念

Map接口在Java中实现了键值对的存储结构,类似于数学中的函数概念,其中每个键(Key)映射到一个唯一的值(Value)。它不是传统意义上的集合,而是一种映射,其中每个键至多映射一个值。

特性
  • 键的唯一性:每个键在Map中只能映射一个值,这意味着Map中不允许键的重复。
  • 无序集合:大多数Map实现(如HashMap)并不保证顺序;然而,某些实现(如LinkedHashMap)则保持了元素添加的顺序。
  • 键值对访问:通过指定键,可以迅速访问其对应的值,这使得Map特别适用于快速查找、删除元素的场景。
主要实现类
  • HashMap:基于哈希表实现,提供了最快的访问速度,不保证映射的顺序。
  • TreeMap:基于红黑树实现,按照键的自然顺序或者构造时提供的Comparator进行排序。
  • LinkedHashMap:保持元素插入的顺序,通常比HashMap慢一点。
常用方法概览
方法功能描述
void put(K key, V value)将指定的值与此映射中的指定键关联。
V get(Object key)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null
void clear()清空当前Map,移除所有的键值对。
V remove(Object key)根据键移除对应的键值对,并返回被移除的值。
int size()返回Map中键值对的数量。
boolean containsKey(Object key)如果此映射包含指定键的映射关系,则返回 true
boolean containsValue(Object value)如果此映射将一个或多个键映射到指定值,则返回 true
Set<K> keySet()返回此映射中包含的键的 Set 视图。
Collection<V> values()返回此映射中包含的值的 Collection 视图。
Set<Map.Entry<K,V>> entrySet()返回此映射中包含的映射关系的 Set 视图。

示例和应用

示例代码
import java.util.HashMap;
import java.util.Map;

public class MapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 1);
        map.put("banana", 2);
        map.put("cherry", 3);

        System.out.println("Apple's count: " + map.get("apple"));
        System.out.println("Map size: " + map.size());

        if (map.containsKey("banana")) {
            System.out.println("Banana is present.");
        }

        map.remove("cherry");
        System.out.println("After removing cherry, keys are: " + map.keySet());
    }
}
运行结果
Apple's count: 1
Map size: 3
Banana is present.
After removing cherry, keys are: [apple, banana]
总结

Map接口为Java集合框架提供了一种强大的数据结构,用于以键值对形式存储和管理数据。其实现类如HashMapTreeMapLinkedHashMap提供了不同的性能特点和排序行为,以适应不同的开发需求。

 

7.6.2 HashMap详解

概述

HashMapMap 接口的一个实现,它使用哈希表来存储映射关系。此实现提供了所有可选的映射操作,并允许使用 null 值和 null 键。HashMap 类大部分方法都是 Map 接口方法的具体实现。

主要特点
  • 无序存储HashMap 不保证映射的顺序;特别是它不保证该顺序恒久不变。
  • 键的唯一性:每个键至多只能映射到一个值。
  • 性能:提供了常数时间的性能,对基本操作(getput)提供快速访问。
示例代码

文件 7-14 Example14.java 演示了 HashMap 的基本用法:

import java.util.*;

public class Example14 {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("1", "张三");
        map.put("2", "李四");
        map.put("3", "王五");

        System.out.println("1: " + map.get("1"));
        System.out.println("2: " + map.get("2"));
        System.out.println("3: " + map.get("3"));

        // 添加相同键的新值会替换旧值
        map.put("3", "赵六");
        System.out.println("3: " + map.get("3"));
    }
}

运行结果示例(图7-23):

1: 张三
2: 李四
3: 赵六
特性分析
  • 键的唯一性:重复添加相同键的元素时,新的值会覆盖旧的值,如上例中键为 "3" 的元素被更新。
  • 值的访问:通过 get() 方法可以通过键快速访问其对应的值。
遍历方法
  1. 使用键集遍历:

     
    Set<String> keySet = map.keySet();
    for (String key : keySet) {
        System.out.println(key + ": " + map.get(key));
    }
    

  2. 使用 entrySet() 遍历:

     
    for (Map.Entry<String, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ": " + entry.getValue());
    }
    

常用操作
  • put():添加键值对到映射中。
  • get():根据键获取值。
  • remove():根据键移除映射中的键值对。
  • containsKey():判断映射中是否包含某个键。
  • size():获取映射中键值对的数量。
实用场景

HashMap 在需要快速查找的场景中非常有用,比如缓存实现、数据库索引等。由于它不保证元素顺序,所以当元素的插入顺序重要时,应考虑使用 LinkedHashMap

7.6.3 LinkedHashMap 详解

概述

LinkedHashMapHashMap 的一个子类,它保留了插入的顺序,这是通过在其内部维护一个双向链表来实现的。这使得迭代访问 LinkedHashMap 时,元素将按照它们的插入顺序返回,不像 HashMap 那样返回无序的集合。

特点
  • 有序性LinkedHashMap 保存了记录的插入顺序,如果需要按自然顺序或任何其他顺序访问键,那么它比 HashMap 更有用。
  • 性能:在迭代访问时比 HashMap 效率更高,因为它使用链表维护内部顺序。
  • 内存开销:相比于 HashMapLinkedHashMap 由于链表的额外维护,其内存占用略高。
示例代码

下面是 LinkedHashMap 的使用示例,展示了其维护插入顺序的特性:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;

public class Example18 {
    public static void main(String[] args) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("3", "李四");
        map.put("2", "王五");
        map.put("4", "赵六");

        Set<String> keySet = map.keySet();
        Iterator<String> it = keySet.iterator();
        while (it.hasNext()) {
            String key = it.next();
            System.out.println(key + ": " + map.get(key));
        }
    }
}
运行结果

运行上述程序将输出:

3: 李四
2: 王五
4: 赵六

可以看到,尽管键 "2" 和 "4" 在 "3" 之后添加,输出的顺序仍然与插入顺序一致。

应用场景

LinkedHashMap 特别适用于需要快速插入和删除元素,同时需要按插入顺序迭代元素的场景。例如,它可以用在最近最少使用(LRU)缓存策略实现中,其中元素每被访问一次,就移动到队列的末尾。

结论

LinkedHashMapMap 接口的一个实现,它通过链表维持了元素的插入顺序。在许多需要同时保持插入顺序和高效映射访问的应用中,LinkedHashMap 是一个理想的选择。

7.6.4 TreeMap

概述

TreeMapMap 接口的一个实现类,提供了一个基于红黑树的 NavigableMap 实现。它保证其元素按照键的自然顺序或者创建时提供的 Comparator 进行排序,支持全序的维护。这意味着,当你遍历 TreeMap 时,每个键会自动按排序顺序出现。

主要特点
  • 有序的键TreeMap 存储的键是有序的,可以按自然排序或者根据构造时提供的 Comparator 进行排序。
  • 键的唯一性:和 HashMap 一样,TreeMap 中的键也是唯一的,重复插入相同键的值会覆盖前者。
  • 高效的查找和访问:由于内部使用红黑树实现,TreeMap 提供对键的有效查找,添加和删除操作。
示例代码
import java.util.TreeMap;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;

public class Example19 {
    public static void main(String[] args) {
        Map<Integer, String> map = new TreeMap<>();
        map.put(3, "李四");
        map.put(2, "王五");
        map.put(4, "赵六");
        map.put(3, "张三"); // 重复键,"张三"会覆盖"李四"

        Set<Integer> keySet = map.keySet();
        Iterator<Integer> it = keySet.iterator();
        while (it.hasNext()) {
            Integer key = it.next();
            System.out.println(key + ": " + map.get(key));
        }
    }
}
运行结果
2: 王五
3: 张三
4: 赵六

如上所示,元素按键的升序排序,并且键 "3" 的值 "张三" 替换了原始的 "李四"。

应用场景

TreeMap 适用于需要大量动态地插入删除键值对,同时需要按照顺序快速访问键值对的场景。例如在实现一个排序的列表或者类似日程管理、任务调度这类需要排序的功能时非常有用。

总结

TreeMap 提供了一种强大的方式来存储键值对,并保证键的排序。其性能保证使其在需要高效访问和顺序访问的同时,也能快速进行插入和删除操作。在使用时,我们需要考虑到其对键的要求——键对象必须实现 Comparable 接口或者在创建 TreeMap 时指定一个 Comparator。这使得 TreeMap 成为 Java 集合框架中功能强大的一个类,尤其是在需要对集合中的键进行有序管理时。

 

7.6.5 Properties

概述

PropertiesHashtable 的一个子类,主要用于处理属性文件。它允许应用程序读取和存储与配置相关的键值对。Properties 集合中的每个键及其对应的值都是一个字符串。

主要特点
  • 字符串键值对Properties 类专门处理字符串类型的键和值,常用于配置数据的存取。
  • 线程安全:由于 Properties 继承自 Hashtable,它是线程安全的。
  • 支持持久化Properties 可以从流中加载数据,也可以把数据存储到流中,便于属性数据的持久化操作。
示例代码
import java.util.Properties;
import java.util.Enumeration;

public class Example21 {
    public static void main(String[] args) {
        Properties p = new Properties();
        // 设置属性
        p.setProperty("Background-color", "red");
        p.setProperty("Font-size", "14px");
        p.setProperty("Language", "chinese");

        // 获取并打印所有属性
        Enumeration<?> names = p.propertyNames();
        while (names.hasMoreElements()) {
            String key = (String) names.nextElement();
            String value = p.getProperty(key);
            System.out.println(key + "=" + value);
        }
    }
}
运行结果
Background-color=red
Font-size=14px
Language=chinese

如上所示,通过 Properties 类可以方便地管理配置数据。所有添加的属性都被正确地存储和检索,展示了 Properties 对属性文件操作的基本用法。

应用场景

Properties 类特别适用于管理配置文件,如应用程序设置、用户偏好和其他需要持久化的参数。这使得 Properties 在多种类型的应用程序中都非常有用,尤其是在需要加载和存储少量配置信息的场合。

总结

Properties 类提供了一种灵活且简单的方式来管理配置数据。它支持从文件加载配置信息以及将配置信息保存到文件,这在实际开发中非常实用。此外,由于其线程安全的特性,Properties 在多线程环境中仍然是安全的,尽管现代应用中更倾向于使用并发集合或其他线程安全机制。总之,Properties 是 Java 标准库中处理轻量级配置数据的一个重要工具。

 

 

 

 

 

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值