HashMap 集合
- 1. 概述
- 2. 方法
- 3. 遍历方式
- 4. 代码示例1
- 5. 代码示例2
- 6. 注意事项
其他集合类
父类 Map
实现类 LinkedHashMap
集合类的遍历方式
具体信息请查看 API 帮助文档
1. 概述
HashMap 是 Java 中的一种集合类,它实现了 Map 接口。HashMap 使用键值对存储数据,每个键值对被称为一个 Entry(条目)。HashMap 使用哈希表来存储数据,因此能够在 O(1) 时间复杂度下进行插入、删除和查找操作。
HashMap 的特点包括:
-
键不重复:HashMap 中的键是唯一的,如果插入时有重复键,则后面的值会覆盖之前的值。
-
无序性:HashMap 中的元素没有固定的顺序,即不保证元素的顺序与插入的顺序一致。
-
允许空键和空值:HashMap 允许键和值都为 null。
-
非线程安全:HashMap 不是线程安全的,如果有多个线程同时访问一个 HashMap 对象并对其进行修改,可能会导致数据不一致或抛出异常。如果需要在多线程环境中使用,可以考虑使用 ConcurrentHashMap。
2. 方法
HashMap
集合是Map
集合的子类,因此Map
集合的方法HashMap
集合都能使用。
Map集合
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
3. 遍历方式
与共有的 集合遍历方式 一样
4. 代码示例1
- 代码示例
存储学生对象并遍历
需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。存储三个键值对元素,并遍历集合
要求:同姓名,同年龄认为是同一个学生
package text.text02;import java.util.*;
import java.util.function.BiConsumer;/*
存储学生对象并遍历
需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。存储三个键值对元素,并遍历集合
要求:同姓名,同年龄认为是同一个学生*/
public class text49 {public static void main(String[] args) {//创建学生对象Student7 student1 = new Student7("张三", 23);Student7 student2 = new Student7("李四", 24);Student7 student3 = new Student7("王五", 25);Student7 student4 = new Student7("王五", 25);//创建集合对象HashMap<Student7, String> hm = new HashMap<>(); //键是自定义对象,必须要重写equals和hashCode方法//添加集合元素hm.put(student1, "山西");hm.put(student2, "河南");hm.put(student3, "湖北");hm.put(student4, "湖北");//遍历集合 、//1.通过键找值的方式遍历System.out.println("1.通过键找值的方式遍历:");Set<Student7> set = hm.keySet();Iterator<Student7> it = set.iterator();while (it.hasNext()) {Student7 key = it.next();String value = hm.get(key);System.out.println(key + " = " + value);}//2.通过键值对的方式遍历System.out.println("2.通过键值对的方式遍历:");Set<Map.Entry<Student7, String>> entries = hm.entrySet();for (Map.Entry<Student7, String> map : entries) {Student7 key = map.getKey();String value = map.getValue();System.out.println(key + " = " + value);}//3.通过结合Lambda表达式的方式遍历System.out.println("3.通过结合Lambda表达式的方式遍历:");hm.forEach(new BiConsumer<Student7, String>() {@Overridepublic void accept(Student7 key, String value) {System.out.println(key + " = " + value);}});}
}class Student7 {private String name;private int age;public Student7() {}public Student7(String name, int age) {this.name = name;this.age = age;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student7 student7 = (Student7) o;return age == student7.age && Objects.equals(name, student7.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}public String toString() {return "Student7{name = " + name + ", age = " + age + "}";}
}
- 输出结果
-
1.通过键找值的方式遍历
-
2.通过键值对的方式遍历
-
3.通过结合Lambda表达式的方式遍历
-
5. 代码示例2
- 代码示例
Map集合案例–统计投票人数
需求:某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点,依次是(A,B,C,D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。
package text.text02;import java.util.*;/*
Map集合案例--统计投票人数
需求:某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点,依次是(A,B,C,D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。*/
public class text50 {public static void main(String[] args) {//计数器方法System.out.println("====================计数器方法==================");method1();//通用方法System.out.println("====================通用方法====================");method2();}//计数器方法public static void method1() {//定义变量记录A,B,C,D四个景点的投票人数int A = 0;int B = 0;int C = 0;int D = 0;//创建集合HashMap<String, Integer> hm = new HashMap<>();//利用随机数模拟随机选择的景点,并利用循环添加进集合Random r = new Random();for (int i = 0; i < 80; i++) {int num = r.nextInt(4);if (num == 0) A++;if (num == 1) B++;if (num == 2) C++;if (num == 3) D++;}//将景点以及每个景点的投票人数添加进去hm.put("A", A);hm.put("B", B);hm.put("C", C);hm.put("D", D);System.out.println("四个景点的投票情况:" + hm);//判断哪个景点投票人数最多//求出投票最多的票数int sum = 0;//定义一个变量记录最多的景点的票数Set<String> set = hm.keySet();for (String key : set) {Integer value = hm.get(key);if (value > sum) {sum = value;}}System.out.println("景点投票最多的票数:" + sum);//遍历map集合,根据投票最多的票数确定景点(可能存在多个景点投票一样的情况)for (String key : set) {Integer value = hm.get(key);if (value == sum) {System.out.println("投票最多的景点:" + key);}}}//通用方法public static void method2() {//定义个数组,存储四个景点String[] arr = {"A", "B", "C", "D"};//定义个集合用来存储每个学生投票的景点ArrayList<String> list = new ArrayList<>();Random r = new Random();//利用循环将学生的投票景点添加进集合for (int i = 0; i < 80; i++) {int index = r.nextInt(arr.length);list.add(arr[index]);}System.out.println("ArrayList集合里的数据:" + list);//创建双列集合用于存储景点名称和票数HashMap<String, Integer> hm = new HashMap<>();//遍历单列集合,并将其中的景点和对应的票数添加进双列集合for (String name : list) {//单列集合中存储的景点名称在双列集合中存在if (hm.containsKey(name)) {//获取该景点的投票数Integer value = hm.get(name);//将投票数+1value++;//再将新的投票数覆盖原来的投票数hm.put(name, value);}//单列集合中存储的景点名称在双列集合中不存在else {hm.put(name, 1);}}System.out.println("HashMap集合里面的数据:" + hm);//判断哪个景点投票人数最多//求出投票最多的票数int sum = 0;//定义一个变量记录最多的景点的票数Set<String> set = hm.keySet();for (String key : set) {Integer value = hm.get(key);if (value > sum) {sum = value;}}System.out.println("景点投票最多的票数:" + sum);//遍历map集合,根据投票最多的票数确定景点(可能存在多个景点投票一样的情况)for (String key : set) {Integer value = hm.get(key);if (value == sum) {System.out.println("投票最多的景点:" + key);}}}
}
- 输出结果
-
计数器方法
-
通用方法
-
6. 注意事项
-
键的唯一性:HashMap 中的键是唯一的,如果插入时有重复键,则后面的值会覆盖之前的值。因此,在使用 HashMap 时要确保键的唯一性,避免出现重复键的情况。
-
键的稳定性:HashMap 的元素没有固定的顺序,也就是说,存入元素的顺序与取出元素时的顺序可能不一致。如果需要按照特定的顺序遍历或操作元素,可以考虑使用 LinkedHashMap。它是 HashMap 的一个子类,保留了元素插入的顺序。
-
hashCode()和equals()方法:HashMap 使用键的 hashCode() 和 equals() 方法来确定键的位置。因此,键的类型必须正确实现这两个方法,以确保正确的插入、查找和删除操作。如果自定义的类作为 HashMap 的键,必须重写 hashCode() 和 equals() 方法,以保证键的唯一性和正确性。
-
并发安全性:HashMap 是非线程安全的,如果有多个线程同时访问一个 HashMap 并对其进行修改,可能会导致数据不一致或抛出异常。如果需要在多线程环境中使用 HashMap,可以考虑使用 ConcurrentHashMap,它是线程安全的。
-
初始容量和负载因子:HashMap 默认的初始容量为 16,并且每次扩容是当前容量的两倍。若事先无法估计容量大小,则可以通过构造函数指定初始容量和负载因子。负载因子表示 HashMap 在容量自动增加之前可以达到的平均负载程度,默认为 0.75。较低的负载因子会减少碰撞,但会增加空间消耗;较高的负载因子会增加碰撞,但会减少空间消耗。根据实际情况选择合适的初始容量和负载因子来平衡空间和时间的开销。