文章目录
Map接口
Map 接口是 Java 集合框架中用于表示键值对的数据结构接口。它提供了一种通过键来查找值的方式,并且键和值都可以是任意的 Java 对象。
Map接口的层次结构
Java中的Map接口定义了映射(key-value对)的通用接口,并提供了常用的操作方法,例如添加、删除、更新和查询元素等。Map接口的实现类可以存储任意类型的键值对,并允许根据key快速查找value。
Map接口层次结构如下:
java.lang.Object
└─ java.util.AbstractMap<K,V>
├─ java.util.HashMap<K,V>
├─ java.util.LinkedHashMap<K,V>
├─ java.util.TreeMap<K,V>
├─ java.util.ConcurrentHashMap<K,V>
├─ java.util.WeakHashMap<K,V>
└─ java.util.IdentityHashMap<K,V>
其中,AbstractMap是一个抽象类,提供了一些通用的方法实现,HashMap是基于哈希表实现的Map,LinkedHashMap是基于链表的Map,TreeMap是基于红黑树实现的Map,ConcurrentHashMap是线程安全的Map,WeakHashMap是使用弱引用的Map,IdentityHashMap是使用对象引用相等判断key的Map。
除了这些标准的实现类之外,用户也可以自定义Map实现类,只需要实现Map接口并提供相应的实现即可。
Map常用方法
方法名 | 说明 |
---|---|
put(K key, V value) | 向 Map 中添加一个键值对 |
get(Object key) | 根据键返回对应的值,如果键不存在则返回 null |
remove(Object key) | 根据键从 Map 中移除对应的键值对 |
containsKey(Object key) | 判断 Map 中是否包含指定的键 |
containsValue(Object value) | 判断 Map 中是否包含指定的值 |
size() | 返回 Map 中键值对的数量 |
isEmpty() | 判断 Map 是否为空 |
keySet() | 返回 Map 中所有键的集合 |
values() | 返回 Map 中所有值的集合 |
entrySet() | 返回 Map 中所有键值对的集合 |
其中,
put()
方法用于向Map
中添加键值对,如果已经存在相同的键,则会覆盖原来的值。get()
方法用于根据键查找对应的值,如果键不存在则返回null
。remove()
方法用于根据键从Map
中移除对应的键值对,如果键不存在则不做任何操作。containsKey()
方法用于判断Map
中是否包含指定的键,返回true
或false
。containsValue()
方法用于判断Map
中是否包含指定的值,返回true
或false
。size()
方法返回Map
中键值对的数量。isEmpty()
方法用于判断Map
是否为空。keySet()
方法返回Map
中所有键的集合,values()
方法返回Map
中所有值的集合,entrySet()
方法返回Map
中所有键值对的集合。
HashMap和TreeMap的区别
- HashMap是基于哈希表实现的Map,其内部结构为数组和链表的组合。其中数组用来存储元素,链表则用来解决哈希冲突。HashMap的键不保证有序。在进行元素的遍历时,其顺序是不确定的。
- TreeMap是基于红黑树实现的Map,其内部结构为平衡二叉树。TreeMap的键是有序的,可以根据键来实现排序。
- 当需要快速添加、删除元素并且不需要关心元素的顺序时,可以选择HashMap;当需要按照键进行排序时,可以选择TreeMap。
LinkedHashMap的特点
LinkedHashMap是基于链表的Map,其内部结构除了具有HashMap的基本结构外,还维护了一个双向链表来记录元素的顺序。LinkedHashMap的键可以按照插入顺序或者访问顺序进行排序。在进行元素的遍历时,其顺序与元素的排序顺序一致。
ConcurrentHashMap的特点
ConcurrentHashMap是线程安全的Map,其内部结构为分段锁的哈希表,可以支持多个线程同时对Map进行操作。它的操作效率比Hashtable要高,因为它只对部分数据进行加锁,不同的线程可以同时访问不同的段,从而提高了并发度。与Hashtable不同的是,ConcurrentHashMap不支持null键和null值。
IdentityHashMap的特点
IdentityHashMap是使用对象引用相等判断key的Map,与使用equals()方法判断相等不同。在IdentityHashMap中,只有当两个key的引用相等时,它们才被视为相等。因此,IdentityHashMap可以用于解决使用对象引用作为键的情况。
WeakHashMap的特点
WeakHashMap是使用弱引用的Map。在WeakHashMap中,如果某个键不再被其它对象引用,那么该键所对应的键值对将被自动删除。WeakHashMap通常用于缓存数据,以避免内存泄漏的问题。
示例代码
示例1:使用 HashMap 实现的 Map 集合对象
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
// 创建 Map 对象
Map<String, String> map = new HashMap<>();
// 添加键值对
map.put("name", "张三");
map.put("age", "20");
map.put("gender", "男");
// 获取键值对
String name = map.get("name");
System.out.println("name: " + name);
// 移除键值对
map.remove("age");
// 判断键是否存在
boolean containsKey = map.containsKey("gender");
System.out.println("containsKey: " + containsKey);
// 判断值是否存在
boolean containsValue = map.containsValue("女");
System.out.println("containsValue: " + containsValue);
// 获取键的集合
Set<String> keySet = map.keySet();
System.out.println("keySet: " + keySet);
// 获取值的集合
Set<String> valueSet = (Set<String>) map.values();
System.out.println("valueSet: " + valueSet);
// 获取键值对的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 判断 Map 是否为空
boolean isEmpty = map.isEmpty();
System.out.println("isEmpty: " + isEmpty);
// 获取 Map 的大小
int size = map.size();
System.out.println("size: " + size);
}
}
这个示例代码中,使用
HashMap
实现了一个Map
对象,添加了多个键值对。然后,通过get()
方法获取指定键的值,通过remove()
方法移除指定键的键值对。还使用了containsKey()
和containsValue()
方法判断键和值是否存在于Map
中。通过keySet()
和values()
方法获取键和值的集合,使用entrySet()
方法获取键值对的集合,并遍历输出了所有的键值对。最后,使用isEmpty()
方法判断Map
是否为空,使用size()
方法获取Map
的大小。
SortedMap的定义
SortedMap 接口继承自 Map 接口,表示一组有序的键值对。其中的键按照升序排列,可以通过键的范围进行导航。SortedMap 接口提供了根据键的范围来获取子映射、获取第一个和最后一个键等方法,同时也提供了各种与 Map 接口相同的方法,如 put、get、containsKey、containsValue 等。
SortedMap 接口中常用的方法
方法名 | 描述 |
---|---|
Comparator<? super K> comparator() | 返回用来对键进行排序的比较器,如果键实现了 Comparable 接口,可以使用自然顺序进行排序 |
SortedMap<K, V> subMap(K fromKey, K toKey) | 返回从 fromKey 到 toKey 范围内的子映射,不包括 toKey |
SortedMap<K, V> headMap(K toKey) | 返回从开始到 toKey 范围内的子映射,不包括 toKey |
SortedMap<K, V> tailMap(K fromKey) | 返回从 fromKey 到结束范围内的子映射,包括 fromKey |
K firstKey() | 返回第一个键 |
K lastKey() | 返回最后一个键 |
SortedMap 接口的实现类包括 TreeMap,它使用红黑树(一种自平衡的二叉查找树)来存储键值对,因此键是有序的。
示例代码
示例1:使用 SortedMap 接口的实现类 TreeMap 来创建并操作有序映射
import java.util.*;
public class SortedMapDemo {
public static void main(String[] args) {
// 创建 SortedMap 对象
SortedMap<String, String> sortedMap = new TreeMap<>();
// 添加键值对
sortedMap.put("1", "one");
sortedMap.put("2", "two");
sortedMap.put("3", "three");
sortedMap.put("4", "four");
// 获取值
String value1 = sortedMap.get("1");
System.out.println("Value of key '1': " + value1);
// 获取子映射
SortedMap<String, String> subMap = sortedMap.subMap("2", "4");
System.out.println("Sub map from '2' to '4': " + subMap);
// 获取第一个和最后一个键
String firstKey = sortedMap.firstKey();
String lastKey = sortedMap.lastKey();
System.out.println("First key: " + firstKey);
System.out.println("Last key: " + lastKey);
// 遍历键值对
for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 删除键值对
sortedMap.remove("3");
// 判断是否包含键或值
boolean containsKey = sortedMap.containsKey("3");
boolean containsValue = sortedMap.containsValue("four");
System.out.println("Contains key '3': " + containsKey);
System.out.println("Contains value 'four': " + containsValue);
}
}
该示例代码首先创建了一个
TreeMap
对象sortedMap
,并向其中添加了一些键值对。然后使用get
方法获取键为"1"
的值,使用subMap
方法获取键的范围在"2"
到"4"
之间的子映射,使用firstKey
和lastKey
方法获取第一个和最后一个键。接下来使用entrySet
方法遍历键值对,使用remove
方法删除键为"3"
的键值对,并使用containsKey
和containsValue
方法判断是否包含键或值。
示例2:使用 Comparable 接口实现SortedMap的key的排序
import java.util.SortedMap;
import java.util.TreeMap;
public class SortedMapExample {
public static void main(String[] args) {
// 创建 SortedMap 对象,使用默认排序方式(基于 key 的自然排序)
SortedMap<Integer, String> map = new TreeMap<>();
map.put(5, "Five");
map.put(3, "Three");
map.put(2, "Two");
map.put(4, "Four");
map.put(1, "One");
// 打印出排序后的元素
for (Integer key : map.keySet()) {
System.out.println(key + " : " + map.get(key));
}
}
}
示例3:使用 Comparator接口(比较器)实现SortedMap的key的排序
import java.util.Comparator;
import java.util.SortedMap;
import java.util.TreeMap;
public class SortedMapExample {
public static void main(String[] args) {
// 创建 SortedMap 对象,使用指定比较器实现排序
SortedMap<Integer, String> map = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1); // 基于 key 的逆序排序
}
});
map.put(5, "Five");
map.put(3, "Three");
map.put(2, "Two");
map.put(4, "Four");
map.put(1, "One");
// 打印出排序后的元素
for (Integer key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
}
}
示例4:基于 Comparable 接口和比较器(Comparator)实现排序
import java.util.*;
public class SortedMapDemo {
public static void main(String[] args) {
// 基于 Comparable 接口实现排序的 SortedMap
SortedMap<Person, String> personMap = new TreeMap<>();
personMap.put(new Person("Tom", 18), "Tom is 18 years old.");
personMap.put(new Person("Alice", 20), "Alice is 20 years old.");
personMap.put(new Person("Bob", 19), "Bob is 19 years old.");
for (Person key : personMap.keySet()) {
System.out.println(key + " - " + personMap.get(key));
}
// 基于 Comparator 实现排序的 SortedMap
SortedMap<Person, String> personMap2 = new TreeMap<>(new PersonComparator());
personMap2.put(new Person("Tom", 18), "Tom is 18 years old.");
personMap2.put(new Person("Alice", 20), "Alice is 20 years old.");
personMap2.put(new Person("Bob", 19), "Bob is 19 years old.");
for (Person key : personMap2.keySet()) {
System.out.println(key + " - " + personMap2.get(key));
}
}
// Person 类实现 Comparable 接口
static class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "(" + age + ")";
}
@Override
public int compareTo(Person o) {
// 先按照年龄排序,如果年龄相同则按照姓名排序
if (this.age != o.age) {
return this.age - o.age;
} else {
return this.name.compareTo(o.name);
}
}
}
// 比较器实现类
static class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
// 先按照年龄排序,如果年龄相同则按照姓名排序
if (o1.age != o2.age) {
return o1.age - o2.age;
} else {
return o1.name.compareTo(o2.name);
}
}
}
}
在这个示例中,我们定义了一个
Person
类,该类实现了Comparable
接口,用于基于对象的自然顺序进行排序。我们同时也定义了一个比较器PersonComparator
,用于在创建SortedMap
对象时指定比较器,实现基于比较器的排序。这个示例中,我们分别创建了两个
SortedMap
对象,一个基于Person
对象的自然顺序进行排序,另一个则是基于PersonComparator
比较器实现排序。在输出时,我们遍历SortedMap
的 key 集合,可以看到输出的 key 都是按照排序规则排好序的。