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 }
View Code

 

第二节  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 }
View Code

 

第四节  补充知识:集合工具类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 }
View Code

  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 }
View Code

  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 }
View Code

  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 }
View Code

  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 }
View Code

  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 }
集合嵌套
posted @ 2022-09-04 11:15  漫漫修行路  阅读(101)  评论(0)    收藏  举报