JAVA进阶--Collection集合之Set系列集合、可变参数、Collections工具类、Map集合体系、集合的嵌套--2022年9月3日
第一节 Set系列集合
1、Set系列

2、HashSet集合元素无序的底层原理:哈希表
a、Set集合的底层原理是什么样的
JDK8之前,哈希表:底层使用数组+链表组成
JDK8开始后,哈希表:底层使用数组+链表+红黑树组成
b、哈希表的详细流程
创建一个默认长度16,默认加载因 为0.75的数组,数组名table
根据元素的哈希值根数组的长度计算出应存入的位置
判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数据。
当数组存满16*0.75=12时,就自动扩容,每次扩容原先的两倍

====================================================================================================

==========================================================================================================

================================================================================================================

3、HashSet元素去重复的底层原理
a、如果希望Set集合认为2个内容相同的对象是重复的应该怎么办
重写对象的hashCode和equals方法

4、LinkedHashSet
a、LinkedHaseSet集合的特点和原理是怎么样的
有序、不重复、无索引
底层基于哈希表,使用双链表记录添加顺序

5、treeSet
a、TreeSet集合的特点是怎么样的
可排序,不重复,无索引
b、TreeSet集合自定义排序规则有几种方式
2种
类实现Comparable接口,重写比较规则
集合自定义Comparator比较器对象,重写比较规则

==============================================================================================

=================================================================================================================


1 package com.itheima.d1_collection_set; 2 3 import java.util.Set; 4 import java.util.TreeSet; 5 6 /** 7 目标:观察TreeSet对于有值特性的数据如何排序。 8 学会对自定义类型的对象进行指定规则排序 9 */ 10 public class SetDemo5 { 11 public static void main(String[] args) { 12 Set<Integer> sets = new TreeSet<>(); // 不重复 无索引 可排序 13 sets.add(23); 14 sets.add(24); 15 sets.add(12); 16 sets.add(8); 17 System.out.println(sets); 18 19 Set<String> sets1 = new TreeSet<>(); // 不重复 无索引 可排序 20 sets1.add("Java"); 21 sets1.add("Java"); 22 sets1.add("angela"); 23 sets1.add("黑马"); 24 sets1.add("Java"); 25 sets1.add("About"); 26 sets1.add("Python"); 27 sets1.add("UI"); 28 sets1.add("UI"); 29 System.out.println(sets1); 30 31 System.out.println("------------------------------"); 32 // 方式二:集合自带比较器对象进行规则定制 33 // 34 // Set<Apple> apples = new TreeSet<>(new Comparator<Apple>() { 35 // @Override 36 // public int compare(Apple o1, Apple o2) { 37 // // return o1.getWeight() - o2.getWeight(); // 升序 38 // // return o2.getWeight() - o1.getWeight(); // 降序 39 // // 注意:浮点型建议直接使用Double.compare进行比较 40 // // return Double.compare(o1.getPrice() , o2.getPrice()); // 升序 41 // return Double.compare(o2.getPrice() , o1.getPrice()); // 降序 42 // } 43 // }); 44 45 Set<Apple> apples = new TreeSet<>(( o1, o2) -> Double.compare(o2.getPrice() , o1.getPrice()) ); 46 apples.add(new Apple("红富士", "红色", 9.9, 500)); 47 apples.add(new Apple("青苹果", "绿色", 15.9, 300)); 48 apples.add(new Apple("绿苹果", "青色", 29.9, 400)); 49 apples.add(new Apple("黄苹果", "黄色", 9.8, 500)); 50 System.out.println(apples); 51 } 52 }
第二节 Collection体系的特点、使用场景总结
1、如果希望元素可以重复,又有索引,索引查询要快?
ArrayList集合,基于数组的(用的最多)
2、如果希望元素可以重复,又有索引,增删首尾操作快
LinkedList集合,基于链表的
3、如果洗完增删改查都快,但是元素不重复、无序、无索引
HashSet集合,基于哈希表的
4、如果希望增删改查都快,但是元素不重复,有序,无索引
LinkedHashSet集合,基于哈希表和双链表的
5、如果要对对象进行排序
TreeSet集合,基于红黑树,后续也可以用List集合实现排序
第三节 补充知识:可变参数

1 package com.itheima.d2_params; 2 3 import java.util.Arrays; 4 5 /** 6 目标:可变参数。 7 8 可变参数用在形参中可以接收多个数据。 9 可变参数的格式:数据类型...参数名称 10 11 可变参数的作用: 12 传输参数非常灵活,方便。 13 可以不传输参数。 14 可以传输一个参数。 15 可以传输多个参数。 16 可以传输一个数组。 17 18 可变参数在方法内部本质上就是一个数组。 19 可变参数的注意事项: 20 1.一个形参列表中可变参数只能有一个!! 21 2.可变参数必须放在形参列表的最后面!! 22 小结: 23 记住。 24 */ 25 public class MethodDemo { 26 public static void main(String[] args) { 27 28 sum(); // 1、不传参数 29 sum(10); // 2、可以传输一个参数 30 sum(10, 20, 30); // 3、可以传输多个参数 31 sum(new int[]{10, 20, 30, 40, 50}); // 4、可以传输一个数组 32 } 33 34 /** 35 注意:一个形参列表中只能有一个可变参数,可变参数必须放在形参列表的最后面 36 * @param nums 37 */ 38 public static void sum( int...nums){ 39 // 注意:可变参数在方法内部其实就是一个数组。 nums 40 System.out.println("元素个数:" + nums.length); 41 System.out.println("元素内容:" + Arrays.toString(nums)); 42 } 43 }
第四节 补充知识:集合工具类Collections
1、
2、
3、
第五节 Collection体系的综合案例:斗地主小游戏
1 package com.itheima.d4_collection_test; 2 3 public class Card { 4 private String size; 5 private String color; 6 private int index; // 牌的真正大小 7 8 public Card(){ 9 } 10 11 public Card(String size, String color, int index) { 12 this.size = size; 13 this.color = color; 14 this.index = index; 15 } 16 17 public String getSize() { 18 return size; 19 } 20 21 public void setSize(String size) { 22 this.size = size; 23 } 24 25 public String getColor() { 26 return color; 27 } 28 29 public void setColor(String color) { 30 this.color = color; 31 } 32 33 public int getIndex() { 34 return index; 35 } 36 37 public void setIndex(int index) { 38 this.index = index; 39 } 40 41 @Override 42 public String toString() { 43 return size + color; 44 } 45 }
1 package com.itheima.d4_collection_test; 2 3 import java.util.*; 4 5 /** 6 目标:斗地主游戏的案例开发。 7 8 业务需求分析: 9 斗地主的做牌, 洗牌, 发牌, 排序(拓展知识), 看牌。 10 业务: 总共有54张牌。 11 点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2" 12 花色: "♠", "♥", "♣", "♦" 13 大小王: "👲" , "🃏" 14 点数分别要组合4种花色,大小王各一张。 15 斗地主:发出51张牌,剩下3张作为底牌。 16 17 功能: 18 1.做牌。 19 2.洗牌。 20 3.定义3个玩家 21 4.发牌。 22 5.排序(拓展,了解,作业) 23 6.看牌 24 */ 25 public class GameDemo { 26 /** 27 1、定义一个静态的集合存储54张牌对象 28 */ 29 public static List<Card> allCards = new ArrayList<>(); 30 31 /** 32 2、做牌:定义静态代码块初始化牌数据 33 */ 34 static { 35 // 3、定义点数:个数确定,类型确定,使用数组 36 String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"}; 37 // 4、定义花色:个数确定,类型确定,使用数组 38 String[] colors = {"♠", "♥", "♣", "♦"}; 39 // 5、组合点数和花色 40 int index = 0; // 记录牌的大小 41 for (String size : sizes) { 42 index++; 43 for (String color : colors) { 44 // 6、封装成一个牌对象。 45 Card c = new Card(size, color, index); 46 // 7、存入到集合容器中去 47 allCards.add(c); 48 } 49 } 50 // 8 大小王存入到集合对象中去 "👲" , "🃏" 51 Card c1 = new Card("" , "🃏", ++index); 52 Card c2 = new Card("" , "👲",++index); 53 Collections.addAll(allCards , c1 , c2); 54 System.out.println("新牌:" + allCards); 55 } 56 57 public static void main(String[] args) { 58 // 9、洗牌 59 Collections.shuffle(allCards); 60 System.out.println("洗牌后:" + allCards); 61 62 // 10、发牌(定义三个玩家,每个玩家的牌也是一个集合容器) 63 List<Card> linhuchong = new ArrayList<>(); 64 List<Card> jiumozhi = new ArrayList<>(); 65 List<Card> renyingying = new ArrayList<>(); 66 67 // 11、开始发牌(从牌集合中发出51张牌给三个玩家,剩余3张作为底牌) 68 // allCards = [🃏, A♠, 5♥, 2♠, 2♣, Q♣, 👲, Q♠ ... 69 // i 0 1 2 3 4 5 6 7 % 3 70 for (int i = 0; i < allCards.size() - 3; i++) { 71 // 先拿到当前牌对象 72 Card c = allCards.get(i); 73 if(i % 3 == 0) { 74 // 请阿冲接牌 75 linhuchong.add(c); 76 }else if(i % 3 == 1){ 77 // 请阿鸠 78 jiumozhi.add(c); 79 }else if(i % 3 == 2){ 80 // 请盈盈接牌 81 renyingying.add(c); 82 } 83 } 84 85 // 12、拿到最后三张底牌(把最后三张牌截取成一个子集合) 86 List<Card> lastThreeCards = allCards.subList(allCards.size() - 3 , allCards.size()); 87 88 // 13、给玩家的牌排序(从大到小 可以自己先试试怎么实现) 89 sortCards(linhuchong); 90 sortCards(jiumozhi); 91 sortCards(renyingying); 92 93 // 14、输出玩家的牌: 94 System.out.println("啊冲:" + linhuchong); 95 System.out.println("啊鸠:" + jiumozhi); 96 System.out.println("盈盈:" + renyingying); 97 System.out.println("三张底牌:" + lastThreeCards); 98 } 99 100 /** 101 给牌排序 102 * @param cards 103 */ 104 private static void sortCards(List<Card> cards) { 105 // cards = [J♥, A♦, 3♥, 🃏, 5♦, Q♥, 2♥ 106 Collections.sort(cards, new Comparator<Card>() { 107 @Override 108 public int compare(Card o1, Card o2) { 109 // o1 = J♥ 110 // o2 = A♦ 111 // 知道牌的大小,才可以指定规则 112 return o2.getIndex() - o1.getIndex(); 113 } 114 }); 115 } 116 117 }
第六节 Map集合体系
1、Map集合的概述
a、Map集合是什么?使用场景是什么样的?
Map集合是键值对集合
Map集合非常适合做类购物车这样的业务场景

2、Map集合体系特点
a、Map集合的特点
HashMap:元素按照键是无序,不重复,无索引,值不做要求(与Map体系一致)
LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求
TreeMap:元素按照键是排序,不重复,无所有的,值不做要求


3、Map集合常用API

1 package com.itheima.d6_map_api; 2 import java.util.Collection; 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.Set; 6 7 /** 8 目标:Map集合的常用API(重点中的重点) 9 - public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。 10 - public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。 11 - public V get(Object key) 根据指定的键,在Map集合中获取对应的值。 12 - public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。 13 - public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。 14 - public boolean containKey(Object key):判断该集合中是否有此键。 15 - public boolean containValue(Object value):判断该集合中是否有此值。 16 */ 17 public class MapDemo { 18 public static void main(String[] args) { 19 // 1.添加元素: 无序,不重复,无索引。 20 Map<String , Integer> maps = new HashMap<>(); 21 maps.put("iphoneX",10); 22 maps.put("娃娃",20); 23 maps.put("iphoneX",100);// Map集合后面重复的键对应的元素会覆盖前面重复的整个元素! 24 maps.put("huawei",100); 25 maps.put("生活用品",10); 26 maps.put("手表",10); 27 // {huawei=100, 手表=10, 生活用品=10, iphoneX=100, 娃娃=20} 28 System.out.println(maps); 29 30 // 2.清空集合 31 // maps.clear(); 32 // System.out.println(maps); 33 34 // 3.判断集合是否为空,为空返回true ,反之! 35 System.out.println(maps.isEmpty()); 36 37 // 4.根据键获取对应值:public V get(Object key) 38 Integer key = maps.get("huawei"); 39 System.out.println(key); 40 System.out.println(maps.get("生活用品")); // 10 41 System.out.println(maps.get("生活用品2")); // null 42 43 // 5.根据键删除整个元素。(删除键会返回键的值) 44 System.out.println(maps.remove("iphoneX")); 45 System.out.println(maps); 46 47 // 6.判断是否包含某个键 ,包含返回true ,反之 48 System.out.println(maps.containsKey("娃娃")); // true 49 System.out.println(maps.containsKey("娃娃2")); // false 50 System.out.println(maps.containsKey("iphoneX")); // false 51 52 // 7.判断是否包含某个值。 53 System.out.println(maps.containsValue(100)); // 54 System.out.println(maps.containsValue(10)); // 55 System.out.println(maps.containsValue(22)); // 56 57 // {huawei=100, 手表=10, 生活用品=10, 娃娃=20} 58 // 8.获取全部键的集合:public Set<K> keySet() 59 Set<String> keys = maps.keySet(); 60 System.out.println(keys); 61 62 System.out.println("------------------------------"); 63 // 9.获取全部值的集合:Collection<V> values(); 64 Collection<Integer> values = maps.values(); 65 System.out.println(values); 66 67 // 10.集合的大小 68 System.out.println(maps.size()); // 4 69 70 // 11.合并其他Map集合。(拓展) 71 Map<String , Integer> map1 = new HashMap<>(); 72 map1.put("java1", 1); 73 map1.put("java2", 100); 74 Map<String , Integer> map2 = new HashMap<>(); 75 map2.put("java2", 1); 76 map2.put("java3", 100); 77 map1.putAll(map2); // 把集合map2的元素拷贝一份到map1中去 78 System.out.println(map1); 79 System.out.println(map2); 80 } 81 }
4、Map集合遍历方式一:键找值

1 package com.itheima.d7_map_traversal; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.Set; 6 7 /** 8 目标:Map集合的遍历方式一:键找值 9 10 Map集合的遍历方式有:3种。 11 (1)“键找值”的方式遍历:先获取Map集合全部的键,再根据遍历键找值。 12 (2)“键值对”的方式遍历:难度较大。 13 (3)JDK 1.8开始之后的新技术:Lambda表达式。(暂时了解) 14 15 a.“键找值”的方式遍历Map集合。 16 1.先获取Map集合的全部键的Set集合。 17 2.遍历键的Set集合,然后通过键找值。 18 小结: 19 代码简单,需要记住! 20 21 */ 22 public class MapDemo01 { 23 public static void main(String[] args) { 24 Map<String , Integer> maps = new HashMap<>(); 25 // 1.添加元素: 无序,不重复,无索引。 26 maps.put("娃娃",30); 27 maps.put("iphoneX",100); 28 maps.put("huawei",1000); 29 maps.put("生活用品",10); 30 maps.put("手表",10); 31 System.out.println(maps); 32 // maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30} 33 34 // 1、键找值:第一步:先拿到集合的全部键。 35 Set<String> keys = maps.keySet(); 36 // 2、第二步:遍历每个键,根据键提取值 37 for (String key : keys) { 38 int value = maps.get(key); 39 System.out.println(key + "===>" + value); 40 } 41 42 } 43 }
5、Map集合遍历方式二:键值对

1 package com.itheima.d7_map_traversal; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.Set; 6 7 /** 8 目标:Map集合的遍历方式。 9 10 Map集合的遍历方式有:3种。 11 (1)“键找值”的方式遍历:先获取Map集合全部的键,再根据键找值。 12 (2)“键值对”的方式遍历:难度较大。 13 (3)JDK 1.8开始之后的新技术:Lambda表达式。 14 15 b.“键值对”的方式遍历: 16 1.把Map集合转换成一个Set集合:Set<Map.Entry<K, V>> entrySet(); 17 2.此时键值对元素的类型就确定了,类型是键值对实体类型:Map.Entry<K, V> 18 3.接下来就可以用foreach遍历这个Set集合,类型用Map.Entry<K, V> 19 */ 20 public class MapDemo02 { 21 public static void main(String[] args) { 22 Map<String , Integer> maps = new HashMap<>(); 23 // 1.添加元素: 无序,不重复,无索引。 24 maps.put("娃娃",30); 25 maps.put("iphoneX",100); 26 maps.put("huawei",1000); 27 maps.put("生活用品",10); 28 maps.put("手表",10); 29 System.out.println(maps); 30 // maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30} 31 /** 32 maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30} 33 👇 34 使用foreach遍历map集合.发现Map集合的键值对元素直接是没有类型的。所以不可以直接foreach遍历集合。 35 👇 36 可以通过调用Map的方法 entrySet把Map集合转换成Set集合形式 maps.entrySet(); 37 👇 38 Set<Map.Entry<String,Integer>> entries = maps.entrySet(); 39 [(huawei=1000), (手表=10), (生活用品=10), (iphoneX=100), (娃娃=30)] 40 entry 41 👇 42 此时可以使用foreach遍历 43 */ 44 // 1、把Map集合转换成Set集合 45 Set<Map.Entry<String, Integer>> entries = maps.entrySet(); 46 // 2、开始遍历 47 for(Map.Entry<String, Integer> entry : entries){ 48 String key = entry.getKey(); 49 int value = entry.getValue(); 50 System.out.println(key + "====>" + value); 51 } 52 } 53 }
6、Map集合遍历方式三:Lambda

1 package com.itheima.d7_map_traversal; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.function.BiConsumer; 6 7 /** 8 目标:Map集合的遍历方式。 9 10 Map集合的遍历方式有:3种。 11 (1)“键找值”的方式遍历:先获取Map集合全部的键,再根据键找值。 12 (2)“键值对”的方式遍历:难度较大。 13 (3)JDK 1.8开始之后的新技术:Lambda表达式。 14 15 c.JDK 1.8开始之后的新技术:Lambda表达式。(暂时了解) 16 */ 17 public class MapDemo03 { 18 public static void main(String[] args) { 19 Map<String , Integer> maps = new HashMap<>(); 20 // 1.添加元素: 无序,不重复,无索引。 21 maps.put("娃娃",30); 22 maps.put("iphoneX",100);// Map集合后面重复的键对应的元素会覆盖前面重复的整个元素! 23 maps.put("huawei",1000); 24 maps.put("生活用品",10); 25 maps.put("手表",10); 26 System.out.println(maps); 27 28 // maps = {huawei=1000, 手表=10, 生活用品=10, iphoneX=100, 娃娃=30} 29 30 // maps.forEach(new BiConsumer<String, Integer>() { 31 // @Override 32 // public void accept(String key, Integer value) { 33 // System.out.println(key + "--->" + value); 34 // } 35 // }); 36 37 maps.forEach((k, v) -> { 38 System.out.println(k + "--->" + v); 39 }); 40 41 } 42 }
7、Map集合案例

1 package com.itheima.d8_map_test; 2 3 import java.util.*; 4 5 /** 6 需求:统计投票人数 7 */ 8 public class MapTest1 { 9 public static void main(String[] args) { 10 // 1、把80个学生选择的数据拿进来。 11 String[] selects = {"A" , "B", "C", "D"}; 12 StringBuilder sb = new StringBuilder(); 13 Random r = new Random(); 14 for (int i = 0; i < 80; i++) { 15 sb.append(selects[r.nextInt(selects.length)]); 16 } 17 System.out.println(sb); 18 19 // 2、定义一个Map集合记录最终统计的结果: A=30 B=20 C=20 D=10 键是景点 值是选择的数量 20 Map<Character, Integer> infos = new HashMap<>(); // 21 22 // 3、遍历80个学生选择的数据 23 for (int i = 0; i < sb.length(); i++) { 24 // 4、提取当前选择景点字符 25 char ch = sb.charAt(i); 26 // 5、判断Map集合中是否存在这个键 27 if(infos.containsKey(ch)){ 28 // 让其值 + 1 29 infos.put(ch , infos.get(ch) + 1); 30 }else { 31 // 说明此景点是第一次被选 32 infos.put(ch , 1); 33 } 34 } 35 36 // 4、输出集合 37 System.out.println(infos); 38 39 } 40 }
8、Map集合的实现类--HashMap

====================================================================================================

=================================================================================================

===================================================================================================

9、Map集合的实现类--LinkedHashMap

10、Map集合的实现类--TreeMap

===========================================================================================

11、Map集合类特点总结

第七节 补充知识:集合的嵌套
1、嵌套结合案例

1 package com.itheima.d9_map_impl; 2 3 import java.util.*; 4 5 /** 6 需求:统计投票人数 7 */ 8 public class MapTest4 { 9 public static void main(String[] args) { 10 // 1、要求程序记录每个学生选择的情况。 11 // 使用一个Map集合存储。 12 Map<String, List<String>> data = new HashMap<>(); 13 14 // 2、把学生选择的数据存入进去。 15 List<String> selects = new ArrayList<>(); 16 Collections.addAll(selects, "A", "C"); 17 data.put("罗勇", selects); 18 19 List<String> selects1 = new ArrayList<>(); 20 Collections.addAll(selects1, "B", "C" , "D"); 21 data.put("胡涛", selects1); 22 23 List<String> selects2 = new ArrayList<>(); 24 Collections.addAll(selects2 , "A", "B", "C" , "D"); 25 data.put("刘军", selects2); 26 27 System.out.println(data); 28 29 // 3、统计每个景点选择的人数。 30 Map<String, Integer> infos = new HashMap<>(); // {} 31 32 // 4、提取所有人选择的景点的信息。 33 Collection<List<String>> values = data.values(); 34 System.out.println(values); 35 // values = [[A, B, C, D], [B, C, D], [A, C]] 36 // value 37 38 for (List<String> value : values) { 39 for (String s : value) { 40 // 有没有包含这个景点 41 if(infos.containsKey(s)){ 42 infos.put(s, infos.get(s) + 1); 43 }else { 44 infos.put(s , 1); 45 } 46 } 47 } 48 49 System.out.println(infos); 50 } 51 }

浙公网安备 33010602011771号