Java Map集合的用法(非常详细)
在 Java 开发中,Map 集合的使用也是比较广泛的。Map 集合以键值对方式存储数据,键和值一一对应,通过键可以获取值,并且键不能重复。
Map 接口的常用实现类有 HashMap、TreeMap、Properties,本节将详细讲解 Map 接口的使用。
Map 集合本身由键(key)的集合和值(value)的集合构成:
这里给出 Map 接口的常用方法,如下表所示:
HashMap 判断两个键是否相同的规则与 HashSet 类似,也是先通过 hashCode() 方法判断键的哈希值是否相同,再通过 equals() 方法判断键的数据是否相等。
HashMap 内部结构和数据存储过程如下图所示:

图 1 HashMap 内部结构和数据存储过程
根据图 1 所示,HashMap 的内部结构是由数组和链表构成的。当向 HashMap 中添加键值对数据时,会先使用键的 hashCode() 方法得到一个哈希值。这个哈希值对应一个集合中的存储位置:
接下来,通过案例来演示 HashMap 集合的使用:
HashMap 中的键是不可重复的,因为键是用 Set 集合存储的。接下来,通过案例来演示 HashMap 的键重复时的情况:
接下来,通过案例来演示 TreeMap 集合的具体用法:
运行之后,结果中可以看到集合中元素顺序并不是这样,而是按键值的大小来升序排列的,这是因为 String 实现了 Comparable 接口,所以默认会按照自然顺序进行排序。
TreeMap 除了可以使用自然顺序进行排序外,还支持定制排序,可以根据自己的需求实现排序逻辑。接下来,通过案例来演示在 TreeMap 集合中实现定制排序:
Hashtable 类因为要确保线程安全,所以存取元素速度比较慢,目前用的比较少。不过它的子类 Properties 在实际开发中用的比较多,该子类对象主要用于处理 properties 属性文件,由于属性文件里的键和值都是字符串类型,所以 Properties 集合里的键和值都是字符串类型。
这里给出 Properties 类的常用方法,如下表所示:
接下来,通过案例来演示 Properties 类的用法:
Map 接口的常用实现类有 HashMap、TreeMap、Properties,本节将详细讲解 Map 接口的使用。
Java Map接口简介
Map 接口与 Collection 接口是并列存在的,它以键值对(key-value)的形式存储元素,可以按照键访问值。Map 集合本身由键(key)的集合和值(value)的集合构成:
- 键的集合是 Set 集合,因此不能有重复的元素,当向 Map 中添加已有的键时,则新的键会覆盖已有的键,通常用 String 类作为 Map 的 key;
- 值的集合是 Collection 集合,可以存在重复元素。Map 中键和值是成对出现的,即通过指定的 key 总能找到唯一与之对应的 value。
这里给出 Map 接口的常用方法,如下表所示:
方法 | 方法描述 |
---|---|
Object put(Object key, Object value) | 以键值对的方式向集合添加数据 |
Object remove(Object key) | 以键为参数删除集合中的键值对数据 |
void putAll(Map t) | 将其他 Map 中的数据添加到当前 Map 集合中 |
void clear() | 清除当前 Map 中的所有数据 |
Object get(Object key) | 根据键获取对应的值,找不到则返回 null |
boolean containsKey(Object key) | 判断集合中是否包含对应的键,包含则返回 true |
boolean containsValue(Object value) | 判断集合中是否包含对应的值,包含则返回 true |
int size() | 返回集合中的记录数 |
boolean isEmpty() | 判断集合是否为空的,空则返回 true |
Set keySet() | 返回集合中键的 Set 视图 |
Collection values() | 返回集合中值的 Collection 视图 |
Set entrySet() | 返回集合中的键值对的 Set 视图 |
Java HashMap集合
HashMap 类是 Map 接口中使用最多的实现类,它的键和值允许为 null。因为它的键也是使用哈希算法进行存储的,所以与 HashSet 集合一样,不保证数据的顺序,另外键也不允许重复。HashMap 判断两个键是否相同的规则与 HashSet 类似,也是先通过 hashCode() 方法判断键的哈希值是否相同,再通过 equals() 方法判断键的数据是否相等。
HashMap 内部结构和数据存储过程如下图所示:

图 1 HashMap 内部结构和数据存储过程
根据图 1 所示,HashMap 的内部结构是由数组和链表构成的。当向 HashMap 中添加键值对数据时,会先使用键的 hashCode() 方法得到一个哈希值。这个哈希值对应一个集合中的存储位置:
- 如果对应的位置上没有元素,则键值对数据可以直接存到这个位置上。
- 如果对应的位置上有数据,则会调用键的 equals() 方法和这个位置上存储的所有元素的键比较一下:
- 如果没有相同的键,则键值对数据会被添加到这个位置上的链表结构中;
- 如果有相同的键,则新添加的键值对数据会覆盖旧的键值对数据。
接下来,通过案例来演示 HashMap 集合的使用:
import java.util.*; public class Demo { public static void main(String[] args) { Map map = new HashMap(); // 创建HashMap集合 map.put(null, null); // 存入键值对,键和值都为null map.put("car1", "布加迪"); // 存入非空数据 map.put("car2", "保时捷"); map.put("car3", "兰博基尼"); System.out.println(map.size()); // 打印集合长度 System.out.println(map); // 打印集合所有元素 System.out.println(map.get("car3")); // 取出并打印键为car3的值 } }程序的运行结果如下:
4
{null=null, car2=保时捷, car3=兰博基尼, car1=布加迪}
兰博基尼
HashMap 中的键是不可重复的,因为键是用 Set 集合存储的。接下来,通过案例来演示 HashMap 的键重复时的情况:
import java.util.*; public class Demo { public static void main(String[] args) { // 创建HashMap集合 Map map = new HashMap(); // 存入元素 map.put("car1", "布加迪"); map.put("car2", "保时捷"); map.put("car3", "兰博基尼"); map.put("car3", "劳斯莱斯"); // 存入重复的键car3 System.out.println(map); // 打印集合所有元素 } }程序的运行结果如下:
{car2=保时捷, car3=劳斯莱斯, car1=布加迪}
以上代码中,键“car3”被添加了两次,第 1 次“car3”值为“兰博基尼”,第 2 次“car3”值为“劳斯莱斯”,当键被重复添加时,后添加的键值覆盖了前面添加的键值。Java TreeMap集合
TreeMap 类也是 Map 接口的一个常用的实现类。TreeMap 集合存储键值对时,会根据键进行排序。该集合可以保证所有的键值对都处于有序状态。接下来,通过案例来演示 TreeMap 集合的具体用法:
import java.util.*; public class Demo { public static void main(String[] args) { Map map = new TreeMap(); // 创建TreeMap集合 map.put("Girl3", "西施"); // 添加元素 map.put("Girl2", "王昭君"); map.put("Girl1", "貂蝉"); map.put("Girl4", "杨玉环"); Iterator iterator = map.keySet().iterator(); // 获取迭代器对象 while (iterator.hasNext()) { Object key = iterator.next(); // 取到键 Object value = map.get(key); // 取到值 System.out.println(key + ":" + value); } } }程序的运行结果如下:
Girl1:貂蝉
Girl2:王昭君
Girl3:西施
Girl4:杨玉环
运行之后,结果中可以看到集合中元素顺序并不是这样,而是按键值的大小来升序排列的,这是因为 String 实现了 Comparable 接口,所以默认会按照自然顺序进行排序。
TreeMap 除了可以使用自然顺序进行排序外,还支持定制排序,可以根据自己的需求实现排序逻辑。接下来,通过案例来演示在 TreeMap 集合中实现定制排序:
import java.util.*; public class Demo { public static void main(String[] args) { // 创建TreeMap集合并传入一个实现了Comparator接口的自定义对象 Map map = new TreeMap(new TestComparator()); // 添加元素 map.put("Girl3", "西施"); map.put("Girl2", "王昭君"); map.put("Girl1", "貂蝉"); map.put("Girl4", "杨玉环"); // 获取迭代器对象 Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { Object key = iterator.next(); // 取到键 Object value = map.get(key); // 取到值 System.out.println(key + ":" + value); } } } class TestComparator implements Comparator { // 自定义类,实现Comparator接口 public int compare(Object o1,Object o2) { // 将Object类型参数强转为String类型 String s1 = (String) o1; String s2 = (String) o2; return s2.compareTo(s1); // 返回比较之后的值 } }程序的运行结果如下:
Girl4:杨玉环 Girl3:西施 Girl2:王昭君 Girl1:貂蝉程序中是按照键为 Girl3、Girl2、Girl1、Girl4 的顺序,将元素存入集合的,运行结果中显示元素是按降序排列的,这是因为本例自定义的 TestComparator 类实现的 compare(Object o1, Object o2)方法重写了排序逻辑,这就是 TreeMap 集合的定制排序。
Java Properties集合
Hashtable 是 Map 接口中一个早期的并且线程安全的实现类。与 HashMap 类似的是,Hashtable 存储的键值对数据也是无序的,它判断键是否相等的方式与 HashMap 类是相同的。但是,与 HashMap 不同的是,它的键和值都不允许使用 null。Hashtable 类因为要确保线程安全,所以存取元素速度比较慢,目前用的比较少。不过它的子类 Properties 在实际开发中用的比较多,该子类对象主要用于处理 properties 属性文件,由于属性文件里的键和值都是字符串类型,所以 Properties 集合里的键和值都是字符串类型。
这里给出 Properties 类的常用方法,如下表所示:
方法 | 方法描述 |
---|---|
String getProperty(String key) | 根据键获取值 |
String getProperty(String key, String defaultValue) | 根据 key 获取对应的值。如果值不存在,则直接将 defaultValue 作为返回值 |
Object setProperty(String key, String value) | 以键值对的方式设置数据。如果键存在,则覆盖之前的数据;如果键不存在,则添加数据 |
void load(InputStream inStream) | 通过输入流从属性文件中加载键值对数据,加载到的键值对数据添加到 Properties 里 |
void store(OutputStream out, String s) | 通过输出流将 Properties 中的键值对输出到指定文件 |
接下来,通过案例来演示 Properties 类的用法:
import java.io.FileOutputStream; import java.util.Properties; public class Demo { public static void main(String[] args) throws Exception { // 创建Properties集合类对象 Properties pro = new Properties(); // 向Properties集合中添加键值对数据 pro.setProperty("username", "AAA"); pro.setProperty("password", "123456"); // 将Properties集合中的属性保存到当前项目根目录下程序自动创建的data.ini文件中 pro.store(new FileOutputStream("data.ini"), "title"); } }上面程序运行后,会在项目根目录下生成一个名为 data.ini 的文件,文件内容如下:
#title
#Wed Jan 13 19:19:44 CST 2021
password=123456
username=AAA