Java的Map
是集合框架中的核心接口之一,用于存储键值对(Key-Value Pairs),通过键(Key)快速查找对应的值(Value)。与List
和Set
不同,Map
是一种双列集合,其核心特点是:
Map
中不能有两个相同的键。LinkedHashMap
或TreeMap
)。特性 | Map | Collection |
---|---|---|
数据结构 | 键值对(Key-Value Pairs) | 单列集合(仅存储值) |
唯一性 | 键唯一,值可重复 | Set 唯一,List 可重复 |
存取方式 | 通过键快速查找值 | 通过索引或迭代器访问元素 |
排序 | 通常无序(TreeMap 可排序) |
List 有序,Set 无序(TreeSet 可排序) |
底层结构:基于哈希表(数组 + 链表/红黑树)。
特点:
null
键和 null
值。O(1)
。适用场景:对性能要求高且不需要线程安全的场景(如缓存、数据映射)。
HashMap 的优化:
链表转红黑树:JDK 8 中,当链表长度超过阈值(默认 8)且哈希表容量达到 64 时,链表会转换为红黑树,查询效率从 O(n)
提升至 O(log n)
。
初始容量与负载因子:
容量 * 负载因子
时扩容。示例代码:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 5); // 添加键值对
map.put("banana", 3);
System.out.println(map.get("apple")); // 输出 5
底层结构:基于红黑树(平衡二叉搜索树)。
特点:
null
键(因为 null
无法比较大小)。O(log n)
。适用场景:需要按键排序的场景(如排行榜、区间查询)。
自定义排序:
Map<String, Integer> treeMap = new TreeMap<>(Comparator.reverseOrder());
treeMap.put("apple", 5);
treeMap.put("banana", 3);
System.out.println(treeMap); // 输出 {banana=3, apple=5}
底层结构:继承自 HashMap
,维护一个双向链表。
特点:
HashMap
。适用场景:需要保持插入顺序或实现 LRU 缓存的场景。
LRU 缓存示例:
Map<String, Integer> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
return size() > 3; // 保留最多 3 个元素
}
};
lruCache.put("apple", 5);
lruCache.put("banana", 3);
lruCache.put("cherry", 2);
lruCache.put("date", 1); // 超出容量,删除最久未使用的 "apple"
null
键和 null
值。底层结构:基于分段锁(Java 8 后优化为 CAS + synchronized)。
特点:
null
值(但不允许 null
键)。Hashtable
。适用场景:多线程环境下需要高性能的并发访问。
并发场景示例:
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("apple", 5);
concurrentMap.computeIfAbsent("banana", k -> 3); // 如果键不存在,则计算并插入
底层结构:
EnumMap
的底层是一个数组,数组的索引由枚举常量的 ordinal()
值决定(即枚举声明的顺序)。EnumMap
的所有键必须是同一个枚举类型,数组长度等于该枚举类型的常量数量。ordinal()
值定位数组下标。特点:
O(1)
:通过枚举的 ordinal()
值直接访问数组。null
键:
null
键会抛出 NullPointerException
。HashMap
一样,EnumMap
不是线程安全的。适用场景:
示例代码:
enum Season { WINTER, SPRING, SUMMER, FALL }
public class EnumMapExample {
public static void main(String[] args) {
EnumMap<Season, String> seasonMap = new EnumMap<>(Season.class);
seasonMap.put(Season.WINTER, "Cold");
seasonMap.put(Season.SPRING, "Warm");
seasonMap.put(Season.SUMMER, "Hot");
seasonMap.put(Season.FALL, "Cool");
// 按枚举声明顺序遍历
for (Season season : Season.values()) {
System.out.println(season + ": " + seasonMap.get(season));
}
}
}
底层结构:
Hashtable
(Java 8 及之前),Java 9+ 改为基于 HashMap
。String
类型(否则会抛出 ClassCastException
)。load(InputStream)
从 .properties
文件加载键值对。store(OutputStream, String)
将键值对保存到文件。特点:
Hashtable
,所有方法同步。Java 9+ 改用 HashMap
,但 Properties
仍通过同步方法保证线程安全。#
或 !
添加注释。defaults
属性设置默认值,键不存在时自动查找。key=value
、key:value
、key value
等格式。null
键或值:
null
键/值会抛出 NullPointerException
。适用场景:
示例代码:
import java.io.*;
import java.util.Properties;
public class PropertiesExample {
public static void main(String[] args) throws IOException {
Properties props = new Properties();
// 从文件加载属性
try (InputStream in = new FileInputStream("config.properties")) {
props.load(in);
}
// 获取属性值
String dbUrl = props.getProperty("database.url");
System.out.println("Database URL: " + dbUrl);
// 设置新属性并保存到文件
props.setProperty("new.key", "new.value");
try (OutputStream out = new FileOutputStream("config.properties")) {
props.store(out, "Updated config");
}
}
}
V put(K key, V value)
插入键值对,若键存在则覆盖旧值,返回旧值。
map.put("apple", 5);
void putAll(Map extends K, ? extends V> m)
合并另一个 Map
的键值对。
map.putAll(anotherMap);
V get(Object key)
返回指定键对应的值,若键不存在则返回 null
。
int count = map.get("banana");
V getOrDefault(Object key, V defaultValue)
返回指定键对应的值,若键不存在则返回默认值。
int count = map.getOrDefault("grape", 0);
V remove(Object key)
删除指定键的键值对,返回被删除的值。
map.remove("apple");
void clear()
清空所有键值对。
map.clear();
boolean containsKey(Object key)
判断是否包含指定键。
boolean hasApple = map.containsKey("apple");
boolean containsValue(Object value)
判断是否包含指定值。
boolean hasFive = map.containsValue(5);
int size()
返回键值对数量。
int size = map.size();
boolean isEmpty()
判断是否为空。
boolean isEmpty = map.isEmpty();
Set
返回所有键的集合。
for (String key : map.keySet()) {
System.out.println(key);
}
Collection
返回所有值的集合。
for (Integer value : map.values()) {
System.out.println(value);
}
Set
返回所有键值对的集合。
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
default void forEach(BiConsumer super K, ? super V> action)
对每个键值对执行操作。
map.forEach((key, value) -> System.out.println(key + ": " + value));
default V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction)
如果键不存在,则计算并插入值。
map.computeIfAbsent("pear", k -> 7);
hashCode()
和 equals()
方法,否则可能导致哈希冲突或查找失败。class CustomKey {
private String name;
private int id;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomKey that = (CustomKey) o;
return id == that.id && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name, id);
}
}
HashMap
)在多线程环境下需使用 Collections.synchronizedMap
包装或选择 ConcurrentHashMap
。Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
hashCode()
和 equals()
方法合理,减少链表或红黑树的使用。HashMap
和 TreeMap
的遍历顺序与插入顺序无关。LinkedHashMap
保持插入顺序或访问顺序(通过构造方法指定)。keySet()
遍历for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
entrySet()
遍历for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
Iterator
遍历 吗,Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
map.entrySet().stream().forEach(entry ->
System.out.println(entry.getKey() + ": " + entry.getValue())
);
Map
自动检查键的唯一性,重复键会覆盖旧值。确保键的 equals()
和 hashCode()
方法正确实现。null
键和 null
值?HashMap
允许 null
键和 null
值,但 TreeMap
不允许 null
键(因为无法比较大小)。Map
?ConcurrentHashMap
或通过 Collections.synchronizedMap
包装普通 Map
。Map
?remove()
方法。如果直接修改 Map
会抛出 ConcurrentModificationException
。HashMap
:高性能、无序、允许 null
。TreeMap
:按键排序。LinkedHashMap
:保持插入顺序或实现 LRU 缓存。ConcurrentHashMap
:高并发环境下的线程安全。put
、putAll
。get
、remove
。keySet
、entrySet
、forEach
。HashMap
或 ConcurrentHashMap
。HashMap
统计频率。TreeMap
按键排序。