Map接口

Map 接口没有继承 Collection 接口,其提供的是 key 到 value 的映射。通过 Map 接口的实现类实现 Map 接口,即可创建 Map 集合。在 Map 集合中不能包含相同的 key,每个 key 只能映射一个 value。key 还决定了存储对象在映射中的存储位置,但不是由 key 对象本身决定的,而是通过一种 “散列技术” 进行处理的,产生一个散列码的整数值。散列码通常被用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。

Map接口概述

Map 接口提供了将 key 映射到值的对象。一个映射不能包含重复的 key,每个 key 最多只能映射到一个值。除集合的常用方法外,Map 接口还提供了如表12.4所示的特殊方法。

image 2024 03 03 20 28 04 570
Figure 1. 表12.4 Map接口中除集合常用方法外的特殊方法

HashMap类

建议使用 HashMap 类实现 Map 集合,因为由 HashMap 类实现的 Map 集合添加和删除映射关系效率更高。可以通过 HashMap 类创建 Map 集合,当需要顺序输出时,再创建一个完成相同映射关系的 TreeMap 类实例。

【例12.6】输出Map集合中书号(键)和书名(值)(实例位置:资源包\TM\sl\12\6)

在项目中创建 HashMapTest 类,先在主方法中创建 Map 集合,再向 Map 集合中添加键值对。其中,key 的值分别为 “ISBN-978654”、“ISBN-978361”、“ISBN-978893”、“ISBN-978756”,value 的值分别为 “Java从入门到精通”、“Android从入门到精通”、“21天学Android”、“21天学Java”。接着,分别获取 Map 集合中的 key 和 value,并把它们分别输出到控制台上。实例代码如下:

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class HashMapTest {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>(); // 创建Map集合对象
		map.put("ISBN-978654", "Java从入门到精通"); // 向Map集合中添加元素
		map.put("ISBN-978361", "Android从入门到精通");
		map.put("ISBN-978893", "21天学Android");
		map.put("ISBN-978756", "21天学Java");
		Set<String> set = map.keySet(); // 构建Map集合中所有key的Set集合
		Iterator<String> it = set.iterator(); // 创建Iterator迭代器
		System.out.println("key值:");
		while (it.hasNext()) { // 遍历并输出Map集合中的key值
			System.out.print(it.next() + " ");
		}
		Collection<String> coll = map.values(); // 构建Map集合中所有value值的集合
		it = coll.iterator();
		System.out.println("\nvalue值:");
		while (it.hasNext()) { // 遍历并输出Map集合中的value值
			System.out.print(it.next() + " ");
		}
	}
}

运行结果如图12.7所示。

image 2024 03 03 20 36 03 560
Figure 2. 图12.7 例12.4的运行结果

遍历Map集合

Map 集合的遍历与 List 集合和 Set 集合的遍历不同。因为 Map 集合有 key(键)和 value(值)两组值,所以遍历 Map 集合时既可以只遍历 key(键),也可以只遍历 value(值),还可以同时遍历 key(键)和 value(值)。

  1. 同时遍历 Map 集合的 key(键)和 value(值)

    在 for 循环中使用 entries 能够同时遍历 Map 集合的 key(键)和 value(值)。这种方式不仅是非常常见的,而且是非常常用的。

    例如,通过 HashMap 类实现 Map 接口,创建一个 Map 集合。向 Map 集合中添加键值对,其中把星期的英文缩合作为 key(键),把星期的中文作为 value(值)。在 for 循环中使用 entries 能够同时遍历 Map 集合的 key(键)和 value(值),并把它们以键值对的形式输出到控制台上。代码如下:

    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) {
            // 创建 Map 集合对象
            Map<String, String> map = new HashMap<>();
            // 向 Map 集合中添加键值对
            map.put("Mon", "星期一");
            map.put("Tue", "星期二");
            map.put("Wed", "星期三");
            map.put("Thu", "星期四");
            map.put("Fri", "星期五");
            map.put("Sat", "星期六");
            map.put("Sun", "星期天");
            // 在 for 循环中使用 entries 遍历 Map 集合
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                System.out.println(key + ": " + value);
            }
        }
    }

    运行结果如下:

         Thu:星期四
         Tue:星期二
         Wed:星期三
         Sat:星期六
         Fri:星期五
         Mon:星期一
         Sun:星期天
  2. 遍历Map集合的key(键)或者value(值)

使用 foreach 循环能够遍历 Map 集合的 key(键)或者 value(值)。

例如,通过 HashMap 类实现 Map 接口,创建一个 Map 集合。向 Map 集合中添加键值对,其中把星期的英文缩合作为 key(键),把星期的中文作为 value(值)。使用 foreach 循环分别遍历 Map 集合的 key(键)和 value(值),并把 key(键)和 value(值)分别输出到控制台上。代码如下:

import java.util.HashMap;public class Test{
    public static void main(String[] args) {
        // 创建 Map 集合对象
        Map<String,String> map = new HashMap<>();
        // 向 Map 集合中添加键值对
        map.put("Mon", "星期一");
        map.put("Tue", "星期二");
        map.put("Wed", "星期三");
        map.put("Thu", "星期四");
        map.put("Fri", "星期五");
        map.put("Sat", "星期六");
        map.put("Sun", "星期天");
        // 输出 key(键)
        for (String key : map.keySet()) {
            System.out.print(key + "\t");
        }
        System.out.println(); // 换行
        // 输出 value(值)
        for (String value : map.values()) {
            System.out.print(value + "\t");
        }
    }
}

运行结果如下:

     Thu     Tue     Wed      Sat        Fri     Mon     Sun
     星期四  星期二    星期三    星期六  星期五  星期一  星期天

TreeMap类

TreeMap 类不仅实现了 Map 接口,还实现了 java.util.SortedMap 接口,因此集合中的映射关系具有一定的顺序。但在添加、删除和定位映射关系时,TreeMap 类比 HashMap 类性能稍差。由于 TreeMap 类实现的 Map 集合中的映射关系是根据键对象按照一定的顺序排列的,因此不允许键对象是 null。

下面通过 TreeMap 类实现 Map 接口,修改例12.4。代码如下:

import java.util.TreeMap;public class TreeMapTest {
    public static void main(String[] args) {
        Map<String, String> map = new TreeMap<>();  // 创建 Map 集合对象
        map.put("ISBN-978654", "Java 从入门到精通");  // 向 Map 集合中添加元素
        map.put("ISBN-978361", "Android 从入门到精通");
        map.put("ISBN-978893", "21 天学 Android");
        map.put("ISBN-978756", "21 天学 Java");
        Set<String> set = map.keySet();  // 构建 Map 集合中所有key的Set集合
        Iterator<String> it = set.iterator();  // 创建 Iterator 迭代器
        System.out.println("key 值:");
        while (it.hasNext()) {
            System.out.print(it.next() + " ");
        }
        Collection<String> coll = map.values(); // 构建 Map 集合中所有 Value 值的集合
        it = coll.iterator();
        System.out.println("\nvalue值:");
        while(it.hasNext()) {
            System.out.print(it.next() + " ");
        }
    }
}

运行结果如图12.8所示。

image 2024 03 04 15 00 00 078
Figure 3. 图12.8 运行结果

Properties类

Properties 类是一个比较特殊的集合,它表示一个持久的属性集,在属性列表中的每个 key(键)及其对应的 value(值)都是一个字符串。Properties 类主要用于读取 Java 的配置文件,其配置文件常为 .properties 文件,属文本文件,是以键值对的形式进行参数配置的。

Properties 类的常用方法及其说明如表12.5所示。

image 2024 03 04 15 01 04 017
Figure 4. 表12.5 Properties类的常用方法及其说明

例如,创建一个 preperties 集合,向该集合中分别添加如下的键值对:连接 MySQL 数据库的驱动、连接 MySQL 数据库的用户名和连接 MySQL 数据库的密码。使用 getProperty() 方法分别获取连接 MySQL 数据库的驱动、用户名和密码,并输出到控制台上。代码如下:

import java.util.Properties;public class Test {
    public static void main(String[] args) {
        // 创建 preperties 集合
        Properties pro = new Properties();
        // 向集合中存储数据
        pro.put("driver", "com.mysql.jdbc.driver");
        pro.put("username", "root");
        pro.put("password", "123456");
        // 取数据
        String v1 = pro.getProperty("driver");
        String v2 = pro.getProperty("username");
        String v3 = pro.getProperty("password");
        // 输出数据
        System.out.println(v1);
        System.out.println(v2);
        System.out.println(v3);
    }
}

运行结果如下:

     com.mysql.jdbc.driver
     root
     123456

再例如,创建一个 preperties 集合,向 preperties 集合中分别添加以下键值对:name 及其值 David、age 及其值 26。使用 store() 方法将 preperties 集合中的键值对存储到当前项目文件夹下的 pro.propreties 文件中。代码如下:

import java.io.FileOutputStream;import java.util.Properties;public class Test {
    public static void main(String[] args) {
        // 创建 propreties 集合
        Properties pro = new Properties();
        pro.put("name", "David");
        pro.put("age", "26");
        // 明确 pro.propreties 文件的路径
        try (FileOutputStream fos = new FileOutputStream("pro.propreties")) {
            // 将集合中的数据存储到 propreties 文件中
            pro.store(fos, "this is a person");  // properties 文件中不可以存储中文
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

找到并打开 pro.propreties 文件后,即可看到如图12.9所示的运行结果。

image 2024 03 04 15 09 07 358
Figure 5. 图12.9 运行结果

编程训练(答案位置:资源包\TM\sl\12\编程训练)

【训练5】省市联动 使用Map接口实现类,输出东北三省的每个省份中的城市名称。

【训练6】模拟2021年NBA扣篮大赛评分 请5位评委(冰人格文、穆大叔、魔术师约翰逊、大鲨鱼奥尼尔和麦蒂)打分,在控制台中输入5个0~10的整数,中间用逗号隔开(如10,9,9,8,10),最后计算5位评委给出的分数之和。