JAVA 集合进阶 06 - 09 Map 集合的实现类:HashMap、LinkecHashMap
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 方法@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic 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//遍历 HashMaphashMap.forEach(new BiConsumer<Student, String>() {@Overridepublic 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.判断哪个景点的次数跟最大值一样,如果一样,打印出来//再次遍历 HashMapSet<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
集合进阶-08-HashMap练习二(利用Map集合进行统计)_哔哩哔哩_bilibili
集合进阶-09-LinkedHashMap_哔哩哔哩_bilibili