1 HashMap 的特点
HashMap 是 Map 里面的一个实现类
没有额外需要学习的特有方法,直接使用 Map 里面的方法就可以了。
特点都是由键决定的:无序、不重复、无索引
HashMap 跟 HashSet 底层原理是一模一样的,都是哈希表结构
2 HashMap 的底层原理
3 HashMap 小结
- HashMap 底层是哈希表结构的
- 依赖 hashCode 方法和 equals 方法保证键的唯一 (hashCode 计算键的哈希值,如果此哈希值位置上存有元素,则需要 equals 来比较键是否一样)
- 如果键存储的是自定义对象,需要重写 hashCode 和 equals 方法
- 如果值存储自定义对象,不需要重写 hashCode 和 equals 方法
4 练习
4.1 练习一 存储学生对象并遍历
创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。
存储三个键值对元素,并遍历
要求:同姓名,同年龄认为是同一个学生
4.1.1 学生类
HashMap的键位置如果存储的是自定义对象,需要重写hashCode和equals方法。
package com.bjpowernode.test19;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//因为 HashMap 键,存的是自定义对象。所以要重写 equals 和 hashCode 方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.1.2 测试类
package com.bjpowernode.test19;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class HashMapDemo1 {
public static void main(String[] args) {
//创建 HashMap 集合
HashMap<Student, String> hashMap = new HashMap<>();
//先创建三个学生对象
Student s1 = new Student("张三", 23);
Student s2 = new Student("李四", 25);
Student s3 = new Student("王五", 21);
Student s4 = new Student("王五", 21);
//添加元素
hashMap.put(s1, "南京");
hashMap.put(s2, "北京");
hashMap.put(s3, "上海");
hashMap.put(s4, "苏州");
//遍历集合
// 第一种遍历方式: 键找值
Set<Student> keys = hashMap.keySet(); //拿到所有的键
for (Student key : keys) { //遍历所有的键 用 for 增强方法
String value = hashMap.get(key); //在 hashmap 中,根据 key 得到 value
//System.out.println( key.getName() + " " + key.getAge() + " " + value);
System.out.println(key + "=" + value); // 需要重写 toString,不然 key 打印出来的是地址
}
System.out.println("------------------------");
// 第二种遍历方式:键值对遍历
Set<Map.Entry<Student, String>> entries = hashMap.entrySet(); //先获取 hashmap 的键值对对象
for (Map.Entry<Student, String> entry : entries) { //通过增强 for 遍历 键值对对象
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " " + value);
}
System.out.println("------------------------");
//第三种遍历方式: Lambda
//遍历 HashMap
hashMap.forEach(new BiConsumer<Student, String>() {
@Override
public void accept(Student student, String s) {
System.out.println(student.getName() + " " + student.getAge() + " " + s);
}
});
System.out.println("------------------------");
//简化后的匿名内部类
hashMap.forEach((student, s) -> System.out.println(student.getName() + " " + student.getAge() + " " + s));
}
}
运行结果
4.2 练习二 统计投票人数
某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A、B、C、D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。
package com.bjpowernode.test19;
import java.util.*;
public class HashMapDemo2 {
public static void main(String[] args) {
// 1 先让同学们投票
//定义一个数组,存储四个景点
String[] arr = {"A", "B", "C", "D"};
//利用随机数模拟 80 个同学的投票,并把投票结果存储起来
ArrayList<String> list = new ArrayList<>(); //先定义一个集合,用来存储投票的结果
Random r = new Random();
for (int i = 0; i < 80; i++) {
list.add(arr[r.nextInt(arr.length)]);
}
//统计
//创建集合
HashMap<String, Integer> hashMap = new HashMap<>();
//遍历 集合 list ,依次得到每个投票信息
for (String s : list) {
// 如果 s 在 hashmap 中存在,则 值 + 1
// 不存在,则添加
if(hashMap.containsKey(s)){ //存在 则值+1
// 先获取当前景点已经被投票的次数
int count = hashMap.get(s); //直接通过键,可以获得对应的值
count++;
hashMap.put(s, count); // 再存回去,这个会覆盖原来的那个键值对!!
} else { //不存在
hashMap.put(s, 1);
}
}
//System.out.println(hashMap); //输出 HashMap 集合
//再次遍历 HashMap ,输出值最大的那个键
int max = 0;
Set<Map.Entry<String, Integer>> entries = hashMap.entrySet(); //键值对遍历
for (Map.Entry<String, Integer> entry : entries) {
if(entry.getValue() >= max){
max = entry.getValue();
}
}
//4.判断哪个景点的次数跟最大值一样,如果一样,打印出来
//再次遍历 HashMap
Set<Map.Entry<String, Integer>> entries1 = hashMap.entrySet();
for (Map.Entry<String, Integer> entry2 : entries1) {
if(entry2.getValue() == max){
System.out.println(entry2.getKey());
}
}
}
}
运行结果:
5 Map 集合的第二个实现类 LinkecHashMap
- 由键决定:有序、不重复、无索引。
- 这里的有序指的是保证存储和取出的元素顺序一致
- 原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
5.1 练习
package com.bjpowernode.test19;
import java.util.LinkedHashMap;
public class LinkedHashMapDemo1 {
public static void main(String[] args) {
//创建集合
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
//添加元素
lhm.put("ccc", 1);
lhm.put("bbb", 2);
lhm.put("aaa", 3);
//打印集合
System.out.println(lhm);
}
}
运行结果:
顺序一致
参考链接:
集合进阶-06-HashMap基本的使用_哔哩哔哩_bilibili
集合进阶-07-HashMap练习一(存储自定义对象)_哔哩哔哩_bilibili