Java HashMap 示例详解
简介
在 Java 编程中,HashMap
是一个极为常用的数据结构。它实现了 Map
接口,用于存储键值对(key-value pairs),能够提供快速的查找、插入和删除操作。通过学习 Java HashMap
的基础概念、使用方法、常见实践以及最佳实践,开发者可以更高效地利用这一强大工具来解决各种实际问题。
目录
- 基础概念
- 什么是
HashMap
- 哈希原理
- 什么是
- 使用方法
- 创建
HashMap
- 添加键值对
- 获取值
- 修改值
- 删除键值对
- 遍历
HashMap
- 创建
- 常见实践
- 存储自定义对象
- 处理空键和空值
- 最佳实践
- 选择合适的初始容量
- 注意哈希冲突
- 避免在迭代时修改
- 小结
基础概念
什么是 HashMap
HashMap
是 Java 集合框架中的一部分,它允许我们存储和检索与特定键相关联的值。每个键值对在 HashMap
中被称为一个 entry
。HashMap
不保证元素的顺序,并且允许一个 null
键和多个 null
值。
哈希原理
HashMap
使用哈希表来存储数据。哈希表是一种基于哈希函数的数据结构,它通过将键的哈希值映射到数组的索引位置来快速定位对应的值。当两个不同的键计算出相同的哈希值时,就会发生哈希冲突。HashMap
使用链地址法(separate chaining)来解决哈希冲突,即当发生冲突时,会将冲突的元素存储在链表或红黑树(JDK 8 引入了红黑树优化)中。
使用方法
创建 HashMap
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
// 创建一个空的 HashMap
HashMap<String, Integer> hashMap = new HashMap<>();
// 创建一个带有初始容量的 HashMap
HashMap<String, Integer> hashMapWithCapacity = new HashMap<>(16);
// 创建一个基于另一个 Map 的 HashMap
Map<String, Integer> anotherMap = new HashMap<>();
anotherMap.put("one", 1);
HashMap<String, Integer> hashMapFromMap = new HashMap<>(anotherMap);
}
}
添加键值对
import java.util.HashMap;
public class HashMapAddExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
hashMap.put("three", 3);
// 如果键已存在,put 方法会覆盖旧的值
hashMap.put("one", 11);
}
}
获取值
import java.util.HashMap;
public class HashMapGetExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
Integer value = hashMap.get("one");
if (value!= null) {
System.out.println("The value for key 'one' is: " + value);
}
// getOrDefault 方法在键不存在时返回默认值
Integer defaultValue = hashMap.getOrDefault("three", 0);
System.out.println("The default value for key 'three' is: " + defaultValue);
}
}
修改值
import java.util.HashMap;
public class HashMapModifyExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
// 直接使用 put 方法修改值
hashMap.put("one", 11);
// compute 方法可以根据键和旧值计算新值
hashMap.compute("one", (key, oldValue) -> oldValue == null? 0 : oldValue + 1);
}
}
删除键值对
import java.util.HashMap;
public class HashMapRemoveExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
// remove 方法根据键删除键值对
hashMap.remove("one");
// remove 方法也可以根据键和值来删除
hashMap.remove("two", 2);
}
}
遍历 HashMap
import java.util.HashMap;
import java.util.Map;
public class HashMapTraversalExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
hashMap.put("three", 3);
// 遍历键
for (String key : hashMap.keySet()) {
System.out.println("Key: " + key);
}
// 遍历值
for (Integer value : hashMap.values()) {
System.out.println("Value: " + value);
}
// 遍历键值对
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 使用 Lambda 表达式遍历
hashMap.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));
}
}
常见实践
存储自定义对象
import java.util.HashMap;
import java.util.Map;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null)? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass()!= obj.getClass())
return false;
Person other = (Person) obj;
if (age!= other.age)
return false;
if (name == null) {
if (other.name!= null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class HashMapCustomObjectExample {
public static void main(String[] args) {
HashMap<Person, String> hashMap = new HashMap<>();
Person person1 = new Person("Alice", 25);
Person person2 = new Person("Bob", 30);
hashMap.put(person1, "Person 1");
hashMap.put(person2, "Person 2");
for (Map.Entry<Person, String> entry : hashMap.entrySet()) {
System.out.println("Key: " + entry.getKey().name + ", Value: " + entry.getValue());
}
}
}
处理空键和空值
import java.util.HashMap;
public class HashMapNullExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put(null, 1);
hashMap.put("key", null);
Integer valueForKey = hashMap.get(null);
Integer valueForNull = hashMap.get("key");
System.out.println("Value for null key: " + valueForKey);
System.out.println("Value for key with null value: " + valueForNull);
}
}
最佳实践
选择合适的初始容量
如果预先知道要存储的元素数量,选择合适的初始容量可以减少哈希表的扩容次数,提高性能。可以使用公式 initialCapacity = (expectedSize / loadFactor) + 1
来计算初始容量。例如:
HashMap<String, Integer> hashMap = new HashMap<>(100);
注意哈希冲突
尽量确保自定义对象的 hashCode
方法能够均匀地分布哈希值,减少哈希冲突。同时,避免使用可变对象作为键,因为对象状态的改变可能会导致哈希值的改变,从而影响 HashMap
的正常操作。
避免在迭代时修改
在遍历 HashMap
时,不要直接调用 remove
或 put
方法修改 HashMap
的结构,这可能会导致 ConcurrentModificationException
。可以使用迭代器的 remove
方法或者创建一个新的 HashMap
来进行修改。例如:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapIterationModificationExample {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
Iterator<Map.Entry<String, Integer>> iterator = hashMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
if ("one".equals(entry.getKey())) {
iterator.remove();
}
}
}
}
小结
Java HashMap
是一个功能强大且常用的数据结构,通过理解其基础概念、掌握使用方法、了解常见实践以及遵循最佳实践,开发者可以在实际项目中高效地使用它。无论是简单的键值对存储,还是复杂的业务逻辑处理,HashMap
都能发挥重要作用。希望本文能帮助读者更深入地理解并运用 Java HashMap
。