Map集合常用API,三种遍历方式,HashMap及其子类LinkedHashMap底层原理详细讲解,TreeMap底层原理详解以及两种排序规则讲解。还有上面这些的练习题和笔记

📅 2026/6/18 9:03:00
Map集合常用API,三种遍历方式,HashMap及其子类LinkedHashMap底层原理详细讲解,TreeMap底层原理详解以及两种排序规则讲解。还有上面这些的练习题和笔记
8、Map双列集合双列集合一次可以添加一对数据双列集合的特点双列集合一次需要存一对数据分别为键和值键不能重复值可以重复键和值是一 一对应的每一个键只能找到自己对应的值键 值这个整体我们称为“键值对”或者“键值对对象”在Java中叫做“Entry对象”1Map的常见APIMap是双列集合的顶层接口它的功能是全部双列集合都可以继承使用的public interface MapK,V{}Map的常见APIV put(K key,V value) 添加元素V remove(Object key) 根据键删除键值对元素void clear() 移除所有的键值对元素boolean containsKey(Object key) 判断集合是否包含指定的键boolean containsValue(Object value) 判断集合是否包含指定的值boolean isEmpty() 判断集合是否为空int size() 集合的长度也就是集合中键值对的个数get(Object key) 如果存在指定的key对象则返回该对象对应的值否则返回nullkeySet() 返回该集合中所有key对象形成的Set集合1put方法的细节在添加数据的时候如果键不存在那么直接把键值对对象添加到map集合当中方法返回null。在添加数据的时候如果键存在那么会把原有的键值对对象覆盖会把被覆盖的值进行返回。2remove方法的细节在删除数据时如果键不存在那么返回null,如果存在返回该对象的值。package MapDemo; import java.util.Map; import java.util.HashMap; public class MapDemo1 { public static void main(String[] args) { MapString,String m new HashMap(); m.put(郭靖,黄蓉); m.put(牢备,孙尚香); System.out.println(m.put(东方曜,西施));//返回null m.put(周瑜,小乔); System.out.println(m.put(东方曜,牢大));//返回西施 System.out.println(m); System.out.println(m.remove(孙策));//返回null System.out.println(m.remove(郭靖));//返回黄蓉 System.out.println(m); // m.clear(); // System.out.println(m); boolean keyResult1 m.containsKey(牢备); boolean keyResult2 m.containsKey(孙尚香); System.out.println(keyResult1 --- keyResult2);//返回true---false boolean valueResult1 m.containsValue(周瑜); boolean valueResult2 m.containsValue(小乔); System.out.println(valueResult1 --- valueResult2);//返回的是false---true System.out.println(m.size()); } }2Map的遍历方式键找值键值对Lambda表达式——1、键找值keySet() 返回该集合中所有key对象形成的Set集合//获取map集合中所有的键把这些键放到一个单列集合当中。例SetString keys map.keySet();V get(Object key) 如果存在指定的key对象则返回该对象对应的值否则返回null//通过get方法获取集合中每个键对应的值。package MapDemo; import java.util.Iterator; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.function.Consumer; public class MapDemo2 { public static void main(String[] args) { MapString,String map new HashMap(); map.put(周瑜,小乔); map.put(孙策,大乔); map.put(云樱,赵怀真); SetString keys map.keySet(); for (String key : keys) { String value map.get(key); System.out.println(key:value); } IteratorString it keys.iterator(); while (it.hasNext()){ String key it.next(); String value map.get(key); System.out.println(key:value); } keys.forEach(new ConsumerString() { Override public void accept(String key) { String value map.get(key); System.out.println(key:value); } }); keys.forEach(key- { String value map.get(key); System.out.println(key:value); }); } }——2、键值对通过键值对对象进行遍历Entry内部类Map中包括一个内部类接口Entry,该类封装了一个key-value对。Entry包含如下三个方法。Object getKey() 返回该Entry里面包含的keyObject getValue() 返回该Entry里面包含的value值Object setValue(V value) 返回该Entry里面包含的value值并返回新设置的value值语法通过map里的的entrySet()方法获取所有的键值对对象返回一个Set集合。如果没有导包SetMap.EntryString,String entries map.entrySet();如果导包import java.util.Map.Entry;SetEntryString,String entries map.entrySet();package MapDemo; import java.util.Iterator; import java.util.Map; import java.util.HashMap; import java.util.Map.Entry; import java.util.Set; import java.util.function.Consumer; public class MapDemo3 { public static void main(String[] args){ MapString,String map new HashMap(); map.put(混子,瑶); map.put(超标,敖隐); map.put(大手,马超); SetEntryString,String entries map.entrySet(); for(Map.EntryString,String entry : entries){ String key entry.getKey(); String value entry.getValue(); System.out.println(key : value); } IteratorMap.EntryString, String it entries.iterator(); while(it.hasNext()) { String key it.next().getKey(); String value map.get(key); System.out.println(key : value); } entries.forEach(new ConsumerEntryString, String() { Override public void accept(Map.EntryString ,String entry) { String key entry.getKey(); String value entry.getValue(); System.out.println(key : value); } }); entries.forEach(entry- { String key entry.getKey(); String value entry.getValue(); System.out.println(key : value); }); } }——3、Lambda表达式Map里面的方法Default void forEach(BiConsumer? super K, ? super V action) 结合Lambda遍历Map集合其中BiConsumerT,U是一个函数式接口package MapDemo; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.function.BiConsumer; public class MapDemo4 { public static void main(String[] args){ MapString,String map new HashMap(); map.put(杀哥,我最讨厌的就是事后道歉~杀~杀~杀~); map.put(坤哥,鸡你太美~); map.put(唐三,复活吧俺的爱人~); map.put(萧炎,侥幸而已~); map.forEach(new BiConsumerString, String() { Override public void accept(String key,String value) { System.out.println(key : value); } }); map.forEach((key, value) - System.out.println(key : value)); } }9、Map的实现类1HashMap———1、HashMap特点和原理HashMap是Map的实现类直接用Map里面的方法就可以了HashMap的特点HashMap是Map里面的一个实现类。没有额外需要学习的特有方法直接使用Map里面的方法就可以了。特点都是由键决定的无序、不重复、无索引HashMap跟HashSet底层原理是一模一样的都是哈希表结构注哈希表JDK8之前由数组和链表组成JDK8及以后是由数组链表红黑树。HashMap的底层原理利用键计算哈希值跟值无关。再计算出在数组中应存入的索引如果索引处为null,则存入如果该索引处已经有元素则只比较键的属性值一样则覆盖原有的键值对对象put 方法的覆盖不一样则添加新的键值对对象JDK8以后新元素直接挂在老元素下面。创建一个默认长度16默认加载因子为0.75的数组数组名table这里的加载因子就是HashMap的扩容时机情况一即当数组里面存了16*0.7512个元素后数组扩容为原来的2倍32。情况二JDK8以后当链表长度大于8而且数组长度大于等于64当前的链表自动转为红黑树提高查找效率根据键的哈希值跟数组的长度计算出应存入的位置公式int index(数组长度-1哈希值判断当前位置是否为null如果是null直接存入如果位置不为null表示有元素则调用equals方法只比较键属性值注意这里如果集合中存储的是自定义对象必须重写equals方法。属性值一样覆盖原有的键值对对象put方法的特点不一样存入数组形成链表因此HashMap保证了元素的唯一JDK8以前新元素存入数组老元素挂在新元素下面形成链表JDK8及以后新元素直接挂在老元素下面形成链表注意如果集合中键存储的是自定义对象必须要重写hashCode和equals方法。如果集合中值存储的是 自定义对象则不需要重写HashCode和equals方法。———2、练习练习一存储自定义对象package MapDemo; import java.util.*; import java.util.Iterator; import java.util.function.BiConsumer; public class MapDemo5 { public static void main(String[] args) { HashMapStudent, String hm new HashMap(); Student s1 new Student(瑶,19); Student s2 new Student(马超,23); Student s3 new Student(孙膑,19); Student s4 new Student(瑶,19); hm.put(s1,混子); hm.put(s2,大手); hm.put(s3,混子); hm.put(s4,老板); SetStudent keys hm.keySet(); for (Student key : keys) { String value hm.get(key); System.out.println(key : value); } SetMap.EntryStudent,String entries hm.entrySet(); IteratorMap.EntryStudent,String it entries.iterator(); while (it.hasNext()) { Map.EntryStudent, String entry it.next(); Student key entry.getKey(); String value entry.getValue(); System.out.println(key : value); } hm.forEach(new BiConsumerStudent, String() { Override public void accept(Student key, String value) { System.out.println(key : value); } }); hm.forEach((key, value) - System.out.println(key : value)); } } class Student { private String name; private int age; public Student() {} public Student(String name, int age) { this.name name; this.age age; } public int getAge() { return age; } public void setAge(int age) { this.age age; } public String getName() { return name; } public void setName(String name) { this.name name; } Override public int hashCode() { return Objects.hash(name,age); } Override public boolean equals(Object obj) { if(this obj)return true; if(obj null || getClass() !obj.getClass()) return false; Student student (Student) obj; return age student.age Objects.equals(name, student.name); } Override public String toString() { return Student [name name , age age ]; } }练习二利用Map集合进行统计package MapDemo; import java.util.*; public class MapDemo6 { public static void main(String[] args) { String[] arr {A,B,C,D}; ArrayListString list new ArrayListString(); Random r new Random(); for (int i 0; i 80; i) { int index r.nextInt(arr.length); list.add(arr[index]); } HashMapString,Integer hm new HashMap(); for(String name : list) { if(hm.containsKey(name)) { int count hm.get(name); count; hm.put(name, count); }else { hm.put(name,1); } } System.out.println(hm); int max 0; SetMap.EntryString, Integer entries hm.entrySet(); for (Map.EntryString, Integer entry : entries) { int count entry.getValue(); if(count max) { max count; } } System.out.println(max); for(Map.EntryString, Integer entry : entries) { int count entry.getValue(); if(count max) { System.out.println(entry.getKey()); } } } }———3、HashMap的子类LinkedHashMapLinkedHashMap由键决定有序、不重复、无索引。和值无关这里的有序指的是保证存储和取出的元素一致原理底层数据结构依然是哈希表只是每个键值对元素有额外的多了一个双链表的机制记录存储的顺序注底层还是利用键计算的哈希值然后equals比较键的属性值。跟值无关package MapAndHashMap; import java.util.LinkedHashMap; public class LinkedHashMap1 { public static void main(String[] args) { LinkedHashMapString, Integer lhm new LinkedHashMap(); lhm.put(c,1); lhm.put(a,3); lhm.put(a,4); lhm.put(b,3); System.out.println(lhm); } } 输出[c1, a4, b3]2TreeMap———1、TreeMap特点和底层原理TreeMapTreeMap跟TreeSet底层原理一样都是红黑树结构的由键决定特性可排序、不重复、无索引可排序对键进行排序注意默认按照键的从小到大进行排序也可以自己规定键的排序规则代码书写两种排序规则实现Comparable接口重写里面的compareTo方法指定比较规则。创建集合时传递Comparator比较器对象重写里面的compare方法指定比较规则。如何选择两种排序规则默认使用第一种但是如果第一种不能满足需求则需要采用第二种排序方式。这里的满足需求是指比如我要比较Integer默认源码是升序我现在要降序第一种也能用但是不推荐修改源码所以可以使用第二种。还有比如说比较字符串源码默认使用ASCII字典序升序排序我现在要降序不可能去修改源码所以用第二种。总结非自定义类型源码中默认比较规则如果要修改该比较规则就用第二种否则用第一种默认即可。———2、TreeMap第一种比较方式实现Comparable接口重写里面的compareTo方法指定比较规则。package TreeMap; import java.util.Map; import java.util.TreeMap; import java.util.Set; import java.util.function.BiConsumer; public class TreeMapDemo2 { public static void main(String[] args) { TreeMapStudent,String tm new TreeMap(); Student s1 new Student(杀哥,19); Student s2 new Student(萧炎,18); Student s3 new Student(坤哥,27); Student s4 new Student(哈哈姐,19); tm.put(s1,我最讨厌的就是事后道歉砰~杀~杀~杀~); tm.put(s2,侥幸而已~); tm.put(s3,大家好我是个人练习生蔡徐坤鸡你太美~); tm.put(s4,仰天大笑出门去我辈岂是读书人~哈哈哈~哈哈哈~); SetStudent keys tm.keySet(); for(Student key : keys) { String value tm.get(key); System.out.println(key : value); } SetMap.EntryStudent,String entries tm.entrySet(); for(Map.EntryStudent,String entry : entries) { Student s entry.getKey(); String value entry.getValue(); System.out.println(s : value); } tm.forEach(new BiConsumerStudent,String() { Override public void accept(Student s,String value) { System.out.println(s : value); } }); tm.forEach((s,value)-System.out.println(s : value)); } } class Student implements ComparableStudent { private String name; private int age; 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; } Override public int compareTo(Student o) { int numthis.getAge() - o.getAge(); if(num0) { return this.getName().compareTo(o.getName()); } return num; } Override public String toString() { return Student [name name , age age ]; } }———3、TreeMap第二种比较方式创建集合时传递Comparator比较器对象重写里面的compare方法指定比较规则。Comparator是函数式接口package TreeMap; import java.util.Comparator; import java.util.TreeMap; public class TreeMapDemo1 { public static void main(String[] args) { TreeMapInteger, String tm new TreeMap(new ComparatorInteger() { Override public int compare(Integer o1, Integer o2) { return o1-o2; } }); TreeMapInteger, String tmm new TreeMap((o1, o2)- o1-o2); tm.put(5,粤利粤); tm.put(2,康帅傅); tm.put(4,九个核桃); tm.put(3,雷碧); tm.put(1,可恰可乐); System.out.println(tm); } } 输出{1可恰可乐, 2康帅傅, 3雷碧, 4九个核桃, 5粤利粤}———4、TreeMap练习统计思路键存字符值存出现次数。统计题可以选择HashMap或者TreeMap.如果题目中要求对结果进行排序默认使用HashMap,因为HashMap速度快如果题目中要求对结果进行排序则使用TreeMap.package TreeMap; import java.util.Map; import java.util.TreeMap; import java.util.Random; import java.util.function.BiConsumer; public class TreeDemo3 { public static void main(String[] args) { String s aababcabcdabcde; TreeMapCharacter, Integer tm new TreeMap(); for (int i 0; i s.length(); i) { char c s.charAt(i); if(tm.containsKey(c)){ int count tm.get(c); count; tm.put(c,count); }else { tm.put(c,1); } } System.out.println(tm); StringBuilder sb new StringBuilder(); tm.forEach(new BiConsumerCharacter, Integer() { Override public void accept(Character key, Integer value) { sb.append(key).append(().append(value).append()); } }); tm.forEach((key, value)- sb.append(key).append(().append(value).append())); System.out.println(sb.toString()); //输出a(5)b(4)c(3)d(2)e(1)a(5)b(4)c(3)d(2)e(1) } }