在Java中,Map
是一种非常重要的数据结构,它允许我们存储键值对(key-value pairs)。下面我会解释一下基本的使用方法,包括添加元素和遍历元素的方式。
Map集合的基本概念
Map
接口是双列集合的一种,用于存储键值对,其中键(key)不允许重复,而值(value)可以重复。
Map的基本操作
创建Map
// 导入Map接口
import java.util.Map;
// 使用HashMap实现,这是最常见的Map实现类
import java.util.HashMap;
// 创建Map实例
Map<String, Integer> map = new HashMap<>();
添加元素
// 向Map中添加元素
map.put("张三", 25);
map.put("李四", 30);
map.put("王五", 25); // 注意,这里键是唯一的,但是值可以重复
Map集合的遍历
基本思路
遍历Map
集合通常需要获取所有的键(keys),然后通过键来查找对应的值(values)。这就像通过丈夫找到妻子一样。
步骤
- 获取所有键的集合
- 遍历键的集合
- 根据键去找值
示例代码
// 获取所有键的集合
Set<String> keys = map.keySet();
// 遍历键的集合
for (String key : keys) {
// 根据键去找值
Integer value = map.get(key);
System.out.println("Key: " + key + ", Value: " + value);
}
使用Entry Set遍历
另一种常见的遍历方式是直接获取Map
中的条目集(entry set),每个条目包含了键值对。这种方式更加高效,因为它只需要遍历一次即可同时访问键和值。
示例代码
// 获取所有条目的集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();
// 遍历条目的集合
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("Key: " + key + ", Value: " + value);
}
小结
Map
集合主要用于存储键值对。- 键是唯一的,而值可以重复。
- 遍历
Map
集合通常涉及获取键的集合或条目的集合,并通过键来获取对应的值。 - 使用条目集(entry set)遍历通常更高效。
HashMap
HashMap
是 Java 中非常常用的一个实现 Map
接口的类,它提供了基于哈希表的数据结构来存储键值对。下面是对 HashMap
的详细介绍,包括其底层结构、依赖的方法以及如何自定义对象作为键。
HashMap的底层结构
HashMap
的底层是一个数组加链表或红黑树的结构。当 HashMap
的大小超过某个阈值时,链表会转换为红黑树以提高查找效率。
- 数组:
HashMap
的底层是一个长度固定的数组,数组的每个位置称为一个槽(bucket)。 - 链表/红黑树:每个槽中存放的是链表或者红黑树的根节点。如果多个键映射到同一个槽中,则它们会被组织成一个链表或者红黑树。
HashMap的工作原理
- 散列函数:当向
HashMap
中插入一个新的键值对时,首先计算键的散列码(通过调用键对象的hashCode()
方法),然后根据散列码计算出该键值对应该被放入哪个槽中。 - 冲突解决:如果两个不同的键散列到了同一个槽中,会发生冲突。
HashMap
使用链地址法来解决冲突,即在一个槽中存放一个链表或红黑树。 - 扩容机制:当
HashMap
的容量达到某个阈值时,它会自动扩容,通常是当前容量的两倍,并重新散列所有键值对。
HashMap依赖的方法
HashMap
的工作依赖于键对象的 hashCode()
和 equals()
方法。
- hashCode():每个键对象必须有一个
hashCode()
方法,该方法返回一个整数散列码,用于确定键值对在HashMap
中的位置。 - equals():当散列冲突发生时,
HashMap
会调用键对象的equals()
方法来判断两个键是否相等。如果两个键相等,那么它们对应的值将被更新或覆盖。
自定义对象作为键
如果你想要使用自定义的对象作为 HashMap
的键,你需要重写该对象的 hashCode()
和 equals()
方法。
示例代码
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
}
public class Main {
public static void main(String[] args) {
HashMap<Person, String> map = new HashMap<>();
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Bob", 30);
map.put(p1, "Developer");
map.put(p2, "Engineer");
System.out.println(map.get(p1)); // Developer
System.out.println(map.get(p2)); // Engineer
}
}
小结
HashMap
依赖于键的hashCode()
和equals()
方法。- 当使用自定义对象作为键时,必须正确地重写这两个方法。
HashMap
的底层是数组加链表或红黑树的结构,这使得它能够高效地存储和检索键值对。