定义:哈希表是一种通过哈希函数组织数据,以支持快速插入和搜索的数据结构。(链表+数组)哈希函数:将任意长度的输入(通常是一个字符串或对象)通过某种算法映射成固定长度的输出(即哈希值),这个输出通常是一个整数。HashMap的基本工作原理:HashMap内部通过数组和链表(或红黑树,在Java 8及以后版本中)的组合来存储键值对。每个键值对都通过哈希函数映射到一个数组的索引上。如果多个键映射到同一个索引(哈希冲突),则这些键值对会被存储在同一个链表(或红黑树)中。冲突解决:由于哈希函数的输出范围有限,不同的输入可能产生相同的输出(即哈希冲突),常见的解决策略有开放寻址法和链地址法。
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
// 创建一个HashMap实例
HashMap
// 向HashMap中添加键值对
ageMap.put("Alice", 30);
ageMap.put("Bob", 25);
ageMap.put("Charlie", 35);
// 访问HashMap中的元素
System.out.println("Alice's age: " + ageMap.get("Alice"));
// 检查HashMap中是否包含某个键
if (ageMap.containsKey("Bob")) {
System.out.println("Bob exists in the map.");
}
// 遍历HashMap
for (Map.Entry
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 使用Java 8的forEach方法遍历
ageMap.forEach((key, value) -> System.out.println(key + ": " + value));
// 移除键值对
ageMap.remove("Bob");
System.out.println("!!! After removing Bob:");
ageMap.forEach((key, value) -> System.out.println(key + " is " + value + " years old."));
// 获取HashMap的大小
System.out.println("The size of the map is: " + ageMap.size());
// 清空HashMap
ageMap.clear();
System.out.println("After clearing the map, its size is: " + ageMap.size());
}
}
HashMap的示例代码:以上是一个简单的HashMap使用示例,演示了如何创建HashMap、添加键值对、访问元素以及遍历HashMap
HashMap的应用场景:
缓存系统:HashMap可以用来实现简单的缓存机制,存储频繁访问的数据以加快访问速度。
import java.util.HashMap;
import java.util.Map;
public class CacheSystemExample {
private static final int MAX_SIZE = 100; // 假设缓存最大容量为100
private Map
// 添加缓存项,如果超出容量则移除最旧的项(这里简化处理,实际可能需要更复杂的逻辑)
public void put(String key, Object value) {
if (cache.size() >= MAX_SIZE) {
// 简化处理:移除第一个元素(实际中可能需要基于LRU等策略)
cache.remove(cache.keySet().iterator().next());
}
cache.put(key, value);
}
// 获取缓存项
public Object get(String key) {
return cache.get(key);
}
public static void main(String[] args) {
CacheSystemExample cache = new CacheSystemExample();
cache.put("user1", "UserInfo1");
cache.put("user2", "UserInfo2");
System.out.println(cache.get("user1")); // 输出: UserInfo1
}
}
数据去重:在处理大量数据时,可以利用HashMap的键唯一性来快速判断数据是否已存在,实现去重功能。
import java.util.HashMap;
import java.util.Set;
public class DataDeduplicationExample {
public static void main(String[] args) {
String[] data = {"apple", "banana", "apple", "orange", "banana", "grape"};
HashMap
for (String item : data) {
if (!seen.containsKey(item)) {
seen.put(item, true);
System.out.println("Unique item: " + item);
}
}
// 或者,如果你只需要去重后的集合
Set
System.out.println("Unique items: " + uniqueItems);
}
}
对象映射:在需要将一种类型的数据映射到另一种类型时,HashMap是非常方便的工具。例如,将用户ID映射到用户对象。
import java.util.HashMap;
import java.util.Map;
class User {
private String id;
private String name;
// 构造函数、getter和setter省略
public User(String id, String name) {
this.id = id;
this.name = name;
}
// ...
}
public class ObjectMappingExample {
public static void main(String[] args) {
Map
userIdMap.put("1", new User("1", "Alice"));
userIdMap.put("2", new User("2", "Bob"));
User user = userIdMap.get("1");
if (user != null) {
System.out.println("User ID 1: " + user.getName()); // 输出: User ID 1: Alice
}
}
}
分组统计:在处理分组统计任务时,可以利用HashMap以某个属性为键,将相关数据聚合在一起。
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Item {
private String category;
private int quantity;
// 构造函数、getter和setter省略
public Item(String category, int quantity) {
this.category = category;
this.quantity = quantity;
}
// ...
}
public class GroupingStatisticsExample {
public static void main(String[] args) {
List
new Item("Fruits", 5),
new Item("Vegetables", 3),
new Item("Fruits", 2),
new Item("Dairy", 4)
);
Map
for (Item item : items) {
categoryCounts.put(item.getCategory(), categoryCounts.getOrDefault(item.getCategory(), 0) + item.getQuantity());
}
for (Map.Entry
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 输出可能包括:
// Fr
使用HashMap的注意事项:
哈希冲突:虽然HashMap通过一系列机制减少冲突,但高冲突率仍可能影响性能。扩容开销:HashMap在达到负载因子时会进行扩容,这是一个相对昂贵的操作,应注意控制负载因子以避免频繁扩容。线程安全:HashMap不是线程安全的,若需并发访问,应考虑使用ConcurrentHashMap。初始容量和负载因子:合理设置初始容量和负载因子可以减少扩容次数,提升性能。
真实案例:
1、使用HashMap实现简单的LRU缓存
LRU(Least Recently Used)缓存是一种常用的页面置换算法,它淘汰最长时间未被使用的数据。使用LinkedHashMap(它继承自HashMap并维护了一个双向链表来记录插入顺序或访问顺序)来实现LRU缓存相对简单。
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true); // 第三个参数true表示让LinkedHashMap按照访问顺序进行排序
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry
// 当Map的大小超过容量时,移除最老的元素
return size() > capacity;
}
// 添加或访问元素的方法,调用put或get方法时会自动调整元素的顺序
// 这里不需要重写put和get方法,LinkedHashMap已经为我们处理了
// 示例使用
public static void main(String[] args) {
LRUCache
cache.put(1, "a");
cache.put(2, "b");
cache.put(3, "c");
System.out.println(cache); // 输出类似: {1=a, 2=b, 3=c}
cache.get(1); // 访问key为1的元素,将其变为最近使用的
cache.put(4, "d"); // 添加新元素,淘汰最久未使用的元素
System.out.println(cache); // 输出类似: {2=b, 3=c, 4=d}
}
}