1 Map集合的介绍
-
java.util.Map<K,V> 集合,里面保存的数据是成对存在的,称之为双列集合。存储的数据,我们称为键值对。 之前所学的Collection集合中元素单个单个存在的,称为单列集合
2 特点
-
Map<K,V> K:键的数据类型;V:值的数据类型
-
特点 :
-
键不能重复,值可以重复
-
键和值是 一 一 对应的,通过键可以找到对应的值
-
(键 + 值) 一起是一个整体 我们称之为“键值对” 或者 “键值对对象”,在Java中叫做“Entry对象”
-
-
使用场景
-
凡是要表示一一对应的数据时就可以Map集合
-
举例 : 学生的学号和姓名 --- (itheima001 小智)
-
举例 : 夫妻的关系 ---- (王宝强 马蓉 ) (谢霆锋 张柏芝)
-
-
3 常用实现类
-
HashMap:
-
此前的HashSet底层实现就是HashMap完成的,HashSet保存的元素其实就是HashMap集合中保存的键,底层结构是哈希表结构,具有键唯一,无序,特点。
-
-
LinkedHashMap:
-
底层结构是有链表和哈希表结构,去重,有序
-
-
TreeMap:
-
底层是有红黑树,去重,通过键排序
-
4 常用的方法
-
public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
-
public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
-
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
-
public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
-
public boolean containKey(Object key):判断该集合中是否有此键。
基本操作示例
import java.util.*;
public class MapExample {
public static void main(String[] args) {
// 创建一个HashMap
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("apple", 5);
map.put("banana", 10);
map.put("orange", 8);
// 获取键对应的值
int numberOfApples = map.get("apple");
System.out.println("Number of apples: " + numberOfApples);
// 遍历Map
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 检查是否包含某个键或值
if (map.containsKey("banana")) {
System.out.println("Map contains key 'banana'");
}
if (map.containsValue(8)) {
System.out.println("Map contains value '8'");
}
// 删除键值对
map.remove("orange");
System.out.println("After removing 'orange', map size: " + map.size());
}
}
5 Map集合的遍历
1. 使用 keySet()
遍历键和值
可以通过 Map
的 keySet()
方法获取所有的键,然后使用这些键来获取对应的值。
Map<String, Integer> map = new HashMap<>();
map.put("apple", 5);
map.put("banana", 10);
map.put("orange", 8);
for (String key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key: " + key + ", Value: " + value);
}
2. 使用 entrySet()
遍历键值对
通过 entrySet()
方法可以获取 Map
中所有的键值对,然后对每个键值对进行操作。
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("Key: " + key + ", Value: " + value);
}
3. 使用 forEach()
方法(Java 8+)
如果你使用的是Java 8及更高版本,可以使用 forEach()
方法结合 Lambda 表达式来遍历 Map
。
map.forEach((key, value) -> {
System.out.println("Key: " + key + ", Value: " + value);
});
4. 遍历值集合
如果你只关心 Map
中的值,可以直接遍历值集合。
for (Integer value : map.values()) {
System.out.println("Value: " + value);
}
6 HashMap
HashMap
是Java中最常用的 Map
实现之一,它基于哈希表实现,提供了快速的插入、删除和查找操作。以下是关于 HashMap
的一些重要特点和使用注意事项:
特点和用法
-
基于哈希表:
HashMap
内部使用哈希表来存储键值对,每个键值对通过计算哈希码存储在数组的某个位置。- 插入、删除、查找操作的平均时间复杂度为 O(1),在理想情况下可以是常数时间。
-
键的唯一性:
- 每个键在
HashMap
中是唯一的,如果插入具有相同键的新值,则会覆盖旧值。
- 每个键在
-
允许键值为
null
:HashMap
允许键和值都为null
,但只能有一个键为null
。
-
不保证顺序:
HashMap
不保证存储键值对的顺序,即使遍历时看起来像有序,也不应依赖此顺序。
- 举例
import java.util.*; public class HashMapExample { public static void main(String[] args) { // 创建一个HashMap Map<String, Integer> hashMap = new HashMap<>(); // 添加键值对 hashMap.put("apple", 10); hashMap.put("banana", 20); hashMap.put("orange", 15); // 获取值 System.out.println("Number of apples: " + hashMap.get("apple")); // 遍历HashMap for (Map.Entry<String, Integer> entry : hashMap.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); } // 删除键值对 hashMap.remove("banana"); System.out.println("After removing 'banana', HashMap: " + hashMap); } }
7 LinkedHashMap
LinkedHashMap
是 Java 中的一种特殊类型的 Map
实现,它继承自 HashMap
,在 HashMap
的基础上增加了对插入顺序或者访问顺序的维护。
特点和用法
-
保持顺序:
LinkedHashMap
可以维护键值对的插入顺序或者访问顺序(最近最少使用,LRU)。插入顺序指的是键值对被添加到Map
中的顺序;访问顺序指的是在使用get
方法获取键值对时,该键值对被认为是最近被访问的,从而放到链表的末尾。- 可以通过构造函数选择保持插入顺序还是访问顺序。
-
线程不安全:
- 与
HashMap
类似,LinkedHashMap
也不是线程安全的。如果需要在多线程环境中使用,应该考虑使用ConcurrentHashMap
或者在使用时手动同步。
- 与
-
实现细节:
LinkedHashMap
使用双向链表维护插入顺序或访问顺序。这个链表负责连接哈希桶中的所有条目(Entry),并在迭代时提供预期的顺序。- 如果指定了访问顺序,则每次调用
get
方法时,相关的条目会被移到链表的末尾,这样最近访问的元素会被保持在最后。 - 举例
import java.util.*; public class LinkedHashMapExample { public static void main(String[] args) { // 创建一个LinkedHashMap,按插入顺序排序 Map<String, Integer> linkedHashMap = new LinkedHashMap<>(); // 添加键值对 linkedHashMap.put("apple", 10); linkedHashMap.put("banana", 20); linkedHashMap.put("orange", 15); // 输出顺序与插入顺序一致 System.out.println("LinkedHashMap entries:"); for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); } // 访问一次 "banana",此时 "banana" 被移到最后 linkedHashMap.get("banana"); // 再次输出,"banana" 现在在最后 System.out.println("After accessing 'banana':"); for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); } } }
8 TreeMap集合
特点和用法
-
有序性:
TreeMap
中的键值对根据键的自然顺序或者自定义的比较器进行排序。默认情况下,键会按照升序排列。- 可以在构造函数中传入一个比较器来自定义排序规则。
-
性能:
TreeMap
提供了基于红黑树的实现,因此插入、删除和查找操作的时间复杂度为 O(log n),其中 n 是TreeMap
中的元素个数。- 这使得
TreeMap
在元素数量较大或需要频繁的插入、删除操作时,性能比较稳定,而不像HashMap
那样在特定情况下会有较差的性能。
-
不允许空键:
TreeMap
不允许键为 null。因为红黑树是根据键来排序和存储的,如果键为 null,无法比较和存储,会导致NullPointerException
。
- 举例
import java.util.*; public class TreeMapExample { public static void main(String[] args) { // 创建一个 TreeMap,按键的自然顺序排序 TreeMap<String, Integer> treeMap = new TreeMap<>(); // 添加键值对 treeMap.put("apple", 10); treeMap.put("banana", 20); treeMap.put("orange", 15); // 输出键值对,按键的升序输出 System.out.println("TreeMap entries:"); for (Map.Entry<String, Integer> entry : treeMap.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); } // 使用自定义比较器,按键的长度降序排序 TreeMap<String, Integer> lengthComparatorMap = new TreeMap<>(Comparator.comparing(String::length).reversed()); lengthComparatorMap.put("apple", 10); lengthComparatorMap.put("banana", 20); lengthComparatorMap.put("orange", 15); // 输出自定义比较器排序后的键值对 System.out.println("Custom Comparator TreeMap entries:"); for (Map.Entry<String, Integer> entry : lengthComparatorMap.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); } } }