赞
踩
Collection集合的格式:
[元素1, 元素2, 元素3, ...]
Map集合的格式:
{key1=value1, key2=value2, key3=value3, ...}
通俗点讲就是,key是老公,value是老婆,都是成双成对的,并且不能出轨。
分析:
购物车购买提供的四个商品和购买数量在后台需要容器存储。
每个商品对象都一一对应一个购买数量。
把商品对象看成是Map集合的键,购买数量看成Map集合的值。
{商品1=2, 商品2=3, 商品3=2, 商品4=3}
1、Map集合是什么?适用场景是什么样的?
都是由键决定的
。键是无序、不重复、无索引,值不做要求
。后面重复的键对应的值
会覆盖前面重复键的值
。键值对都可以为null
HashMap:元素按照键是无序、不重复、无索引,值不做要求。(与Map(父亲)体系一致)
LinkedHashMap:元素按照键是有序
、不重复、无索引,值不做要求。
排序
、不重复、无索引,值不做要求。1、Map集合的特点是什么样的?
有序
、不重复、无索引,值不做要求。排序
、不重复、无索引,值不做要求。Map的API如下:
方法 | 说明 |
---|---|
V put(K key, V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
V get(Object key) | 根据键获取对应的值 |
Set< K > keyset() | 获取全部键的集合 |
Collection< V > values() | 获取全部值的集合 |
void clear() | 移除所有键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
void putAll(Map<? extends K, ? extends V> m) | 把一个集合中的所有元素拷贝到另一个集合中去 |
package com.app.d8_map_api; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** 目标:掌握Map集合体系的常用API */ public class MapAPIDemo1 { public static void main(String[] args) { // 1、添加元素:无序、不重复、无索引。 Map<String, Integer> maps = new HashMap<>(); maps.put("李宁音速6", 10); maps.put("娃娃", 20); maps.put("李宁音速6", 100); // Map集合后面的键对应的元素,会覆盖前面重复的整个键值对元素。 maps.put("华为nova7", 100); maps.put("毛巾", 10); maps.put("手表", 10); System.out.println(maps); // {手表=10, 李宁音速6=100, 华为nova7=100, 娃娃=20, 毛巾=10} // 2、清空集合 // maps.clear(); // System.out.println(maps); System.out.println("-----------------------------------"); // 3、判断集合是否为空,为空返回true,反之! System.out.println(maps.isEmpty()); System.out.println("-----------------------------------"); // 4、根据键获取对应值 Integer key = maps.get("李宁音速6"); System.out.println(key); // 100 System.out.println(maps.get("华为nova7")); // 100 System.out.println(maps.get("华为nova9")); // null System.out.println("-----------------------------------"); // 5、根据键删除整个元素。(删除键会返回键的值) System.out.println(maps.remove("娃娃")); System.out.println(maps); System.out.println("-----------------------------------"); // 6、判断是否包含某个键,包含返回true,反之! System.out.println(maps.containsKey("华为nova7")); // true System.out.println(maps.containsKey("娃娃")); // false System.out.println(maps.containsKey("娃娃2")); // false System.out.println("-----------------------------------"); // 7、判断是否包含某个值,包含返回true,反之! System.out.println(maps.containsValue(100)); // true System.out.println(maps.containsValue(10)); // false System.out.println(maps.containsValue(33)); // false System.out.println("-----------------------------------"); // {手表=10, 李宁音速6=100, 华为nova7=100, 娃娃=20, 毛巾=10} // 8、获取全部键的集合:Set<K> keySet() // 为什么用Set集合来接?因为Set集合:无序、不重复、无索引,符合Map集合的键的特点 Set<String> keys = maps.keySet(); System.out.println(keys); // [李宁音速6, 华为nova7, 娃娃, 毛巾] System.out.println("-----------------------------------"); // 9、获取全部值的集合:Collection<V> values() // 为什么用Collection集合来接?因为Collection集合:可重复,可以保留重复的值 Collection<Integer> values = maps.values(); System.out.println(values); // [10, 100, 100, 10] System.out.println("-----------------------------------"); // 10、集合的大小 System.out.println(maps.size()); // 4,因为键值对是一个整体 System.out.println("----------------拓展---------------"); // 11、合并其他Map集合。(拓展) Map<String, Integer> map1 = new HashMap<>(); map1.put("java1", 1); map1.put("java2", 100); Map<String, Integer> map2 = new HashMap<>(); map2.put("java2", 1); map2.put("java3", 100); map1.putAll(map2); // 把集合map2的元素拷贝一份到map1中去 System.out.println(map1); System.out.println(map2); } }
{手表=10, 李宁音速6=100, 华为nova7=100, 娃娃=20, 毛巾=10} ----------------------------------- false ----------------------------------- 100 100 null ----------------------------------- 20 {手表=10, 李宁音速6=100, 华为nova7=100, 毛巾=10} ----------------------------------- true false false ----------------------------------- true true false ----------------------------------- [手表, 李宁音速6, 华为nova7, 毛巾] ----------------------------------- [10, 100, 100, 10] ----------------------------------- 4 ----------------拓展--------------- {java3=100, java2=1, java1=1} {java3=100, java2=1} Process finished with exit code 0
取出全部键的集合后,遍历键的Set集合,然后根据键找对应的值。
方法 | 说明 |
---|---|
Set< K > keySet() | 获取所有键的集合 |
V get(Object key) | 根据键获取值 |
package com.app.d9_map_traverse; import java.util.HashMap; import java.util.Map; import java.util.Set; /** 目标:掌握Map集合的遍历方式一:键找值 */ public class MapTraverseDemo1 { public static void main(String[] args) { // 创建一个Map集合,添加一些数据 Map<String, Integer> maps = new HashMap<>(); maps.put("宇智波鼬手办", 20); maps.put("Nike跑鞋", 100); maps.put("手表", 20); maps.put("U盘", 2000); System.out.println("遍历前:" + maps); // {手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100} System.out.println(); // 键找值遍历方式 // 1、先获取全部键的集合 Set<String> keys = maps.keySet(); // 2、遍历全部的键 System.out.println("遍历后:"); for (String key : keys) { // 根据键得到对应的值 int value = maps.get(key); System.out.println(key + "==>" + value); } } }
遍历前:{手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100}
遍历后:
手表==>20
宇智波鼬手办==>20
U盘==>2000
Nike跑鞋==>100
Process finished with exit code 0
方法 | 说明 |
---|---|
Set< Map.Entry< K, V > > entrySet() | 获取所有键值对对象的集合 |
K getKey() | 获取键 |
V getValue() | 获取值 |
package com.app.d9_map_traverse; import java.util.HashMap; import java.util.Map; import java.util.Set; /** 目标:掌握Map集合的遍历方式二:键值对 */ public class MapTraverseDemo2 { public static void main(String[] args) { // 创建一个Map集合,添加一些数据 Map<String, Integer> maps = new HashMap<>(); maps.put("宇智波鼬手办", 20); maps.put("Nike跑鞋", 100); maps.put("手表", 20); maps.put("U盘", 2000); System.out.println("遍历前:" + maps); // {手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100} System.out.println(); /* {手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100} ☟ 使用foreach遍历Map集合,发现Map集合的键值对元素是没有直接类型的,因此不能直接foreach遍历集合。 ☟ 通过调用Map集合的API,entrySet()方法把Map集合转换成Set集合形式:maps.entrySet()。 方法内部其实也是先将全部键和全部值遍历出来,然后将键和值封装成一个对象,这样就可以作为一个对象遍历了 [(手表=20), (宇智波鼬手办=20), (U盘=2000), (Nike跑鞋=100)] entry ☟ Set<Map.Entry<String, Integer>> entries = maps.entrySet(); ☟ 此时可以使用foreach遍历这个键值对对象了 */ // 1、把Map集合转换成Set集合形式:将键值对封装成一个对象 Set<Map.Entry<String, Integer>> entries = maps.entrySet(); // 2、使用foreach遍历这个键值对对象 System.out.println("遍历后:"); for (Map.Entry<String, Integer> entry : entries){ String key = entry.getKey(); // 获取键 int value = entry.getValue(); // 获取值 System.out.println(key + "==>" + value); } } }
遍历前:{手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100}
遍历后:
手表==>20
宇智波鼬手办==>20
U盘==>2000
Nike跑鞋==>100
Process finished with exit code 0
方法 | 说明 |
---|---|
default void forEach(BiConsumer<? super K, ? super V> action) | 结合lambda遍历Map集合 |
package com.app.d9_map_traverse; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; /** 目标:掌握Map集合的遍历方式三:结合lambda表达式遍历Map集合 */ public class MapTraverseDemo3 { public static void main(String[] args) { // 创建一个Map集合,添加一些数据 Map<String, Integer> maps = new HashMap<>(); maps.put("宇智波鼬手办", 20); maps.put("Nike跑鞋", 100); maps.put("手表", 20); maps.put("U盘", 2000); System.out.println("遍历前:" + maps); // {手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100} System.out.println(); // 1、使用JDK8后的新技术,结合lambda遍历map // {手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100} /* 分析: 其实forEach()内部是用方式二帮我们遍历的: 先将Map集合转换成Set集合形式:将键值对封装成一个对象; 取出键和值,回调accept()方法,分别将键和值传送给这里 */ /*maps.forEach(new BiConsumer<String, Integer>() { @Override public void accept(String key, Integer value) { System.out.println(key + "==>" + value); } });*/ System.out.println("遍历后:"); maps.forEach(( k, v) -> System.out.println(k + "==>" + v) ); } }
遍历前:{手表=20, 宇智波鼬手办=20, U盘=2000, Nike跑鞋=100}
遍历后:
手表==>20
宇智波鼬手办==>20
U盘==>2000
Nike跑鞋==>100
Process finished with exit code 0
package com.app.d10_map_test; import java.util.HashMap; import java.util.Map; import java.util.Random; /** 需求: 某个班级80名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A、B、C、D), 每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。 */ public class MapTest { public static void main(String[] args) { // 1、将80个学生选择的景点拿到程序中。 // a、提供四个景点给学生选择:A B C D(个数确定、类型确定。数组存) String[] selects = {"A", "B", "C", "D"}; // b、创建随机数对象,用于随机一个索引,模拟学生选择景点 Random rd = new Random(); // c、创建StringBuilder对象,用于拼接80名学生的选择结果 StringBuilder sb = new StringBuilder(); // d、模拟80名学生选择景点 for (int i = 0; i < 80; i++) { // e、拼接80名学生选择的结果 sb.append(selects[rd.nextInt(selects.length)]); } System.out.println("随机选择结果:" + sb); // 80名学生的最终选择结果 // 2、定义Map集合用于存储最终统计的结果。例如:选择A景点=30名学生,B=20,C=20,D=10。键是景点,值是选择数量 Map<Character, Integer> infos = new HashMap<>(); // 3、遍历80个学生选择的景点,看Map集合中是否存在,不存在存入 “某景点=1”,存在则其对应值+1。 // a、定义循环遍历80名学生选择的景点 for (int i = 0; i < sb.length(); i++) { // b、提取当前选择的景点字符 char attraction = sb.charAt(i); // c、判断当前选择的景点是否存在于集合中 if (infos.containsKey(attraction)){ // 存在,说明此景点不是第一次被选择,让其景点的选择票数+1 infos.put(attraction, infos.get(attraction) + 1); }else { // 不存在,说明此景点是第一次被选择,让其景点的选择票数为1 infos.put(attraction, 1); } } // System.out.println("最终统计票数:" + infos); // 4、统计完选择票数后,优化输出 infos.forEach( (k, v) -> System.out.println("景点" + k + "的选择票数:" + v) ); } }
随机选择结果:CBCCADAACCAABCDCCBBACBDBDDDDBBDABCDAACBDDABCDDDDABDDDAABCCCDABCCBBCABDDBDAABADBC
景点A的选择票数:18
景点B的选择票数:20
景点C的选择票数:19
景点D的选择票数:23
Process finished with exit code 0
只需要自己控制程序一步一步往下走,就可以看完整个执行流程了!!
如果已经明白了整个流程,不想看了,可以结束Debug的执行:
HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
,只是HashMap的每个元素包含两个值(键值对)而已。
实际上:Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。
HashMap的添加原理:
将键、值作为一个Entry对象,然后获取Entry对象的哈希值,对底层位置求余,存入求余结果对应的位置。
如果下一个要添加的元素也算到了同一个位置,就会形成链表,当链表长度超过8,就会自动转换为红黑树。
1、HashMap的特点和底层原理是什么样的?
由键决定:无序、不重复、无索引。
HashMap底层是哈希表结构的。
依赖hashCode和equals方法保证键
的唯一。
如果键
要存储的是自定义对象,需要重写hashCode和equals方法。
有序
、不重复、无索引。底层数据结构依然是哈希表,只是每个键值对元素额外多了一个双链表的机制记录存储的顺序。
将要添加的键值对封装成一个对象,然后对底层数组长度求余,存入求余结果对应的位置;
然后上一个元素记住下一个元素的地址,下一个元素又记住上一个元素的地址,形成一个双链表。
可排序
、不重复、无索引。TreeMap跟TreeSet的底层原理是一样的。
实际上:TreeSet底层是基于TreeMap设计的。
package com.app.d11_map_impl; /** 自定义类:猫类。 指定规则排序方式一: 让自定义的类实现Comparable接口重写里面的compareTo方法,来自定义比较规则。 */ public class Cat implements Comparable<Cat>{ /** 猫的属性:昵称、毛色、价格、重量 */ private String name; private String color; private double price; private int weight; /** * 重写Comparable接口的compareTo方法,来自定义比较规则。 * @param o 接收一个猫对象 * @return */ @Override public int compareTo(Cat o) { // 自定义比较规则:按照猫的重量升序排序 return this.weight - o.weight; // 去除重量重复的数据 // return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的数据 } public Cat(){ } public Cat(String name, String color, double price, int weight) { this.name = name; this.color = color; this.price = price; this.weight = weight; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", color='" + color + '\'' + ", price=" + price + ", weight=" + weight + '}'; } }
package com.app.d11_map_impl; import java.util.Collections; import java.util.Comparator; import java.util.Map; import java.util.TreeMap; /** 目标:掌握Map集合的实现类:TreeMap 特点:可排序、不重复、无索引 */ public class TreeMapDemo3 { public static void main(String[] args) { // 多态写法 // 1、默认排序 Map<Integer, String> cats = new TreeMap<>(); cats.put(13, "小花猫"); cats.put(2, "小黑猫"); cats.put(23, "小白猫"); cats.put(1, "小黄猫"); cats.forEach( (k, v) -> System.out.println(k + " : " + v) ); System.out.println("------------------------------------"); // Map<Cat, String> students = new TreeMap<>(); // 一行经典代码 // 2、自定义排序规则: // 方式二:集合自定义Comparator比较器对象,重写比较规则。 // 按照猫的价格来降序排序 Map<Cat, String> students = new TreeMap<>((o1, o2) -> Double.compare(o2.getPrice(), o1.getPrice()) ); students.put(new Cat("胖球", "花白色", 899.9, 40), "广西"); students.put(new Cat("咪咪", "白色", 666.5, 40), "湖北"); students.put(new Cat("小黑", "黑色", 899.8, 25), "广州"); students.put(new Cat("虾皮", "黄色", 566.9, 33), "安徽"); students.forEach( (k, v) -> System.out.println(k + " = " + v) ); } }
1 : 小黄猫
2 : 小黑猫
13 : 小花猫
23 : 小白猫
------------------------------------
Cat{name='胖球', color='花白色', price=899.9, weight=40} = 广西
Cat{name='小黑', color='黑色', price=899.8, weight=25} = 广州
Cat{name='咪咪', color='白色', price=666.5, weight=40} = 湖北
Cat{name='虾皮', color='黄色', price=566.9, weight=33} = 安徽
Process finished with exit code 0
package com.app.d11_map_impl; import java.util.*; /** 目标:通过案例导学,理解集合嵌套 需求:某个班级多名学生,现在需要组成秋游活动,班长提供了四个景点依次是(A、B、C、D), 每个学生可以选择多个景点,请统计出最终哪个景点想去的人数最多。 */ public class MapTest4 { public static void main(String[] args) { // 1、模拟多名学生选择景点,记住每个学生选择的情况 // a、创建一个集合存储学生选择的景点数据 Map<String, List<String>> data = new HashMap<>(); // b、将学生选择的景点数据存入集合中 List<String> stuSelects1 = new ArrayList<>(); // 创建一个集合用于存储学生选择的景点数据 Collections.addAll(stuSelects1, "A", "C"); // 存储学生选择的景点数据 data.put("张飞", stuSelects1); // 将学生选择的景点数据存入集合 List<String> stuSelects2 = new ArrayList<>(); Collections.addAll(stuSelects2, "B", "C", "D"); data.put("关羽", stuSelects2); List<String> stuSelects3 = new ArrayList<>(); Collections.addAll(stuSelects3, "A", "B", "C", "D"); data.put("赵云", stuSelects3); System.out.println("所有学生的选择情况:" + data); // 所有学生的选择情况:{关羽=[B, C, D], 张飞=[A, C], 赵云=[A, B, C, D]} // values // 2、统计多名学生的最终投票人数 // a、创建集合用于统计每个景点的投票人数 Map<String, Integer> infos = new HashMap<>(); // b、得到所有人选择的景点数据(值) Collection<List<String>> values = data.values(); //System.out.println("所有人选择的景点数据:" + values); // 所有人选择的景点数据:[[B, C, D], [A, C], [A, B, C, D]] // value // c、循环遍历所有人选择的景点数据 for (List<String> value : values) { // [B, C, D] // a // d、循环遍历单个人选择的景点数据 for (String a : value) { // e、判断此景点是否存在于集合中 if (infos.containsKey(a)) { // 存在,说明此景点不是第一次被选择,让其选择数量+1 infos.put(a, infos.get(a) + 1); }else { // 不存在,说明此景点是第一次被选择,让其选择数量为1 infos.put(a, 1); } } } // 3、统计完每个景点的投票人数,优化输出 infos.forEach((k, v) -> System.out.println("景点" + k + "的投票人数:" + v)); } }
所有学生的选择情况:{关羽=[B, C, D], 张飞=[A, C], 赵云=[A, B, C, D]}
景点A的投票人数:2
景点B的投票人数:2
景点C的投票人数:3
景点D的投票人数:2
Process finished with exit code 0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。