day08【Collections、Set、Map、斗地主排序】

今日内容

  • Collections工具类
  • Set集合———>重点
  • Map集合——>重点
  • 练习

教学目标

  • 能够使用集合工具类
  • 能够使用Comparator比较器进行排序
  • 能够使用可变参数
  • 能够说出Set集合的特点
  • 能够说出哈希表的特点
  • 使用HashSet集合存储自定义元素
  • 能够说出Map集合特点
  • 使用Map集合添加方法保存数据
  • 使用”键找值”的方式遍历Map集合
  • 使用”键值对”的方式遍历Map集合
  • 能够使用HashMap存储自定义键值对的数据
  • 能够完成斗地主洗牌发牌案例

第一章 Collections类

知识点— Collections常用功能

目标

  • 能够使用集合工具类Collections

路径

  • 代码演示

讲解

  • java.utils.Collections是集合工具类,用来对集合进行操作。
    常用方法如下:

  • public static void shuffle(List<?> list):打乱集合顺序。

  • public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。

  • public static <T> void sort(List<T> list,Comparator<? super T> com ):将集合中元素按照指定规则排序。

代码演示:

  1. /**
  2. * public static void shuffle(List<?> list):打乱集合中元素的顺序。
  3. */
  4. private static void method01() {
  5. // 创建一个List集合对象,限制集合中元素类型为Integer
  6. List<Integer> list = new ArrayList<>();
  7. // 往集合中添加一些元素
  8. list.add(300);
  9. list.add(100);
  10. list.add(200);
  11. list.add(500);
  12. list.add(400);
  13. System.out.println("打乱顺序之前:"+list);// 打乱顺序之前:[300, 100, 200, 500, 400]
  14. // 随机打乱集合中元素的顺序:public static void shuffle(List<?> list)
  15. Collections.shuffle(list);
  16. System.out.println("打乱顺序之后:"+list);
  17. }
  18. /**
  19. * public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
  20. * 集合中的元素为系统类的对象
  21. */
  22. private static void method02() {
  23. // 创建一个List集合对象,限制集合中元素类型为Integer
  24. List<Integer> list = new ArrayList<>();
  25. // 往集合中添加一些元素
  26. list.add(300);
  27. list.add(100);
  28. list.add(200);
  29. list.add(500);
  30. list.add(400);
  31. System.out.println("排序之前的集合:"+list);// 打乱顺序之前:[300, 100, 200, 500, 400]
  32. // 将集合中元素按照默认规则排序: public static <T> void sort(List<T> list)
  33. Collections.sort(list);
  34. System.out.println("排序之后的集合:"+list);// 排序之后的集合:[100, 200, 300, 400, 500]
  35. }

我们的集合按照默认的自然顺序进行了排列,如果想要指定顺序那该怎么办呢?

小结

知识点— Comparator比较器

目标

  • 能够使用Comparator比较器进行排序

路径

  • 代码演示

讲解

  1. public static void main(String[] args) {
  2. /*
  3. Collections常用功能:
  4. - public static void shuffle(List<?> list):打乱集合中元素的顺序。
  5. - public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
  6. 默认规则: 事先写好的规则
  7. 对集合中的元素按照默认规则排序,要求该集合元素所属的类实现Comparable接口,重写compareTo()方法
  8. 然后在compareTo()方法中指定排序的默认规则
  9. - public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。
  10. 指定规则: 自己定义的规则
  11. 参数Comparator<T>接口:也称比较器接口,用来指定排序的规则
  12. */
  13. // 创建一个List集合对象,限制集合中元素类型为Integer
  14. List<Integer> list = new ArrayList<>();
  15. // 往集合中添加一些元素
  16. list.add(300);
  17. list.add(100);
  18. list.add(200);
  19. list.add(500);
  20. list.add(400);
  21. System.out.println("排序之前的集合:"+list);// 打乱顺序之前:[300, 100, 200, 500, 400]
  22. // 300 100 200 500 400
  23. // 300
  24. // 对list集合指定规则排序: 降序
  25. Collections.sort(list, new Comparator<Integer>() {
  26. @Override
  27. public int compare(Integer o1, Integer o2) {
  28. // 指定排序规则
  29. // 前减后:升序
  30. // 后减前:降序
  31. // 前:第一个参数 o1
  32. // 后:第二个参数 o2
  33. return o2 - o1;
  34. }
  35. });
  36. System.out.println("排序之后的集合:"+list);// 排序之后的集合:[500, 400, 300, 200, 100]
  37. // 对list集合指定规则排序: 升序
  38. Collections.sort(list, new Comparator<Integer>() {
  39. @Override
  40. public int compare(Integer o1, Integer o2) {
  41. // 指定排序规则
  42. // 前减后:升序
  43. // 后减前:降序
  44. // 前:第一个参数 o1
  45. // 后:第二个参数 o2
  46. return o1 - o2;
  47. }
  48. });
  49. System.out.println("排序之后的集合:"+list);// 排序之后的集合:[100, 200, 300, 400, 500]
  50. }

小结

知识点— 可变参数

目标

  • 能够使用可变参数

路径

  • 可变参数的使用
  • 注意事项
  • 应用场景: Collections

讲解

可变参数的使用

JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化.

格式:

  1. 修饰符 返回值类型 方法名(参数类型... 形参名){ }

代码演示:

  1. public class Demo {
  2. public static void main(String[] args) {
  3. // 可变参数的语法
  4. /*int[] arr = {10, 20, 30, 40, 50, 60};
  5. // 调用method1方法
  6. method1(10, 20, 30, 40, 50);
  7. // 调用method2方法
  8. method2(arr);
  9. method2(10, 20, 30, 40, 50, 60);
  10. //
  11. method3(arr);
  12. method3(10, 20, 30, 40, 50, 60);
  13. method4(10,"jack","rose");*/
  14. }
  15. public static void method4(int num,String... str){
  16. }
  17. // 定义一个方法,可以接收5个int类型的参数
  18. public static void method3(int[] arr) {
  19. for (int i : arr) {
  20. System.out.println(i);
  21. }
  22. System.out.println(arr[0]);
  23. }
  24. // 定义一个方法,可以接收5个int类型的参数
  25. public static void method2(int... num) {
  26. for (int i : num) {
  27. System.out.println(i);
  28. }
  29. System.out.println(num[0]);
  30. }
  31. // 定义一个方法,可以接收5个int类型的参数
  32. public static void method1(int num1, int num2, int num3, int num4, int num5) {
  33. }
  34. }

注意事项

  1. 1.一个方法只能有一个可变参数
  2. 2.如果方法中有多个参数,可变参数要放到最后。

应用场景: Collections

  1. Collections中也提供了添加一些元素方法:
  2. `public static <T> boolean addAll(Collection<T> c, T... elements)`:往集合中添加一些元素。

代码演示:

  1. public class CollectionsDemo {
  2. public static void main(String[] args) {
  3. ArrayList<Integer> list = new ArrayList<Integer>();
  4. //原来写法
  5. //list.add(12);
  6. //list.add(14);
  7. //list.add(15);
  8. //list.add(1000);
  9. //采用工具类 完成 往集合中添加元素
  10. Collections.addAll(list, 5, 222, 12);
  11. System.out.println(list);
  12. }

小结

第二章 Set接口

知识点—Set接口介绍

目标

  • Set接口介绍

路径

  • Set接口

讲解

  1. Set接口:也称Set集合,但凡是实现了Set接口的类都叫做Set集合
  2. 特点:元素无索引,元素存取无序,元素不可重复(唯一)
  3. 实现类:
  4. HashSet集合:元素无索引,元素存取无序,元素不可重复(唯一)
  5. LinkedHashSet集合:元素无索引,元素存取有序,元素不可重复(唯一)
  6. TreeSet集合:元素无索引,元素存取无序,元素不可重复(唯一),元素可排序
  7. 注意:
  8. 1.Set集合并没有特有的功能,都是使用Collection父接口中的方法
  9. 2.Set集合元素无索引,所以遍历方式只能是:迭代器,增强for循环

小结

知识点—HashSet集合

目标

  • 能够说出HashSet集合的特点

路径

  • HashSet集合的特点

讲解

java.util.HashSetSet接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不能保证不一致)。

我们先来使用一下Set集合存储,看下现象,再进行原理的讲解:

  1. public class Test {
  2. public static void main(String[] args) {
  3. /*
  4. HashSet集合的特点:
  5. HashSet集合(类): 存储数据的数据结构,哈希表结构,元素唯一,元素无索引,元素存取无序
  6. */
  7. // 创建一个HashSet集合,限制集合中元素的类型为String类型
  8. HashSet<String> set = new HashSet<>();
  9. // 往集合中添加元素
  10. set.add("nba");
  11. set.add("cba");
  12. set.add("bac");
  13. set.add("abc");
  14. set.add("nba");
  15. System.out.println(set);// [cba, abc, bac, nba]
  16. }
  17. }

小结

知识点—HashSet集合存储数据的结构(哈希表)

目标

  • 哈希表底层结构以及HashSet保证元素唯一原理

路径

  • 哈希表底层结构
  • HashSet保证元素唯一原理

讲解

哈希表底层结构

JDK1.8之前,哈希表底层采用数组+链表实现,即使用数组处理冲突,同一hash值的链表都存储在一个数组里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示。

day08【Collections、Set、Map、斗地主排序】 - 图1

HashSet保证元素唯一原理
  1. HashSet集合保证元素唯一的原理:底层是哈希表结构,哈希表保证元素唯一依赖于hashCode()和equals方法();
  2. 1.HashSet集合存储元素的时候,就会调用该元素的hashCode()方法计算哈希值
  3. 2.判断该哈希值位置上,是否有相同哈希值的元素
  4. 3.如果该哈希值位置上没有相同哈希值的元素,那么就直接存储
  5. 4.如果该哈希值位置上有相同哈希值的元素,那么就产生了哈希冲突
  6. 5.如果产生了哈希冲突,就得调用该元素的equals()方法与该哈希值位置上的所有元素进行一一比较:
  7. 如果该哈希值位置上有任意一个元素与该元素相等,那么就不存储
  8. 如果该哈希值位置上所有元素与该元素都不相等,那么就直接存储
  9. 补充:
  10. Object类: hashCode()和equals()方法;
  11. hashCode():Object类中的hashCode()方法是根据地址值计算哈希值
  12. equals方法():Object类中的equals()方法是比较地址值
  1. public class Demo {
  2. public static void main(String[] args) {
  3. // 创建一个HashSet集合,限制集合中元素的类型为String
  4. HashSet<String> set = new HashSet<>();
  5. // 往集合中添加一些元素
  6. set.add("nba");
  7. set.add("cba");
  8. set.add("bac");
  9. set.add("abc");
  10. set.add("nba");
  11. // 遍历打印集合
  12. for (String e : set) {
  13. System.out.println(e);// cba abc bac nba
  14. }
  15. System.out.println("nba".hashCode());// nba:108845
  16. System.out.println("cba".hashCode());// cba:98274
  17. System.out.println("bac".hashCode());// bac:97284
  18. System.out.println("abc".hashCode());// abc:96354
  19. }
  20. }

小结

知识点— HashSet存储自定义类型元素

1.目标

  • 使用HashSet集合存储自定义元素

2.路径

  • 代码演示

3.讲解

给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一.

  1. public class Person{
  2. /**
  3. * 姓名
  4. */
  5. public String name;
  6. /**
  7. * 年龄
  8. */
  9. public int age;
  10. public Person() {
  11. }
  12. public Person(String name, int age) {
  13. this.name = name;
  14. this.age = age;
  15. }
  16. @Override
  17. public String toString() {
  18. return "Person{" +
  19. "name='" + name + '\'' +
  20. ", age=" + age +
  21. '}';
  22. }
  23. @Override
  24. public boolean equals(Object o) {
  25. if (this == o) return true;
  26. if (o == null || getClass() != o.getClass()) return false;
  27. Person person = (Person) o;
  28. return age == person.age &&
  29. Objects.equals(name, person.name);
  30. }
  31. @Override
  32. public int hashCode() {
  33. return Objects.hash(name, age);
  34. }
  35. }

创建测试类:

  1. public class Demo {
  2. public static void main(String[] args) {
  3. // 创建多个Person对象
  4. Person p1 = new Person("张三", 18);
  5. Person p2 = new Person("李四", 38);
  6. Person p3 = new Person("王五", 28);
  7. Person p4 = new Person("张三", 18);
  8. // 创建HashSet集合对象,限制集合中元素的类型为Person
  9. HashSet<Person> set = new HashSet<>();
  10. // 往集合中添加Person对象
  11. set.add(p1);
  12. set.add(p2);
  13. set.add(p3);
  14. set.add(p4);
  15. // 遍历打印集合中的元素
  16. for (Person p : set) {
  17. System.out.println(p);
  18. }
  19. System.out.println(p1.hashCode());
  20. System.out.println(p2.hashCode());
  21. System.out.println(p3.hashCode());
  22. System.out.println(p4.hashCode());
  23. }
  24. }

小结

知识点— LinkedHashSet

目标

  • 使用LinkedHashSet保证元素怎么存就怎么取,即存取有序

路径

  • 代码演示

讲解

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?

在HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

演示代码如下:

  1. public class LinkedHashSetDemo {
  2. public static void main(String[] args) {
  3. Set<String> set = new LinkedHashSet<String>();
  4. set.add("bbb");
  5. set.add("aaa");
  6. set.add("abc");
  7. set.add("bbc");
  8. Iterator<String> it = set.iterator();
  9. while (it.hasNext()) {
  10. System.out.println(it.next());
  11. }
  12. }
  13. }
  14. 结果:
  15. bbb
  16. aaa
  17. abc
  18. bbc

小结

知识点— TreeSet集合

目标

  • 知道使用TreeSet集合的特点并能够使用TreeSet集合

路径

  • 代码演示

讲解

特点

TreeSet集合是Set接口的一个实现类,底层依赖于TreeMap,是一种基于红黑树的实现,其特点为:

  1. 元素唯一
  2. 元素没有索引
  3. 使用元素的自然顺序对元素进行排序,或者根据创建 TreeSet 时提供的 Comparator 比较器
    进行排序,具体取决于使用的构造方法:
  1. public TreeSet(): 根据其元素的自然排序进行排序
  2. public TreeSet(Comparator<E> comparator): 根据指定的比较器进行排序

演示

案例演示自然排序(20,18,23,22,17,24,19):

  1. public static void main(String[] args) {
  2. //无参构造,默认使用元素的自然顺序进行排序
  3. TreeSet<Integer> set = new TreeSet<Integer>();
  4. set.add(20);
  5. set.add(18);
  6. set.add(23);
  7. set.add(22);
  8. set.add(17);
  9. set.add(24);
  10. set.add(19);
  11. System.out.println(set);
  12. }
  13. 控制台的输出结果为:
  14. [17, 18, 19, 20, 22, 23, 24]

案例演示比较器排序(20,18,23,22,17,24,19):

  1. public static void main(String[] args) {
  2. //有参构造,传入比较器,使用比较器对元素进行排序
  3. TreeSet<Integer> set = new TreeSet<Integer>(new Comparator<Integer>() {
  4. @Override
  5. public int compare(Integer o1, Integer o2) {
  6. //元素前 - 元素后 : 升序
  7. //元素后 - 元素前 : 降序
  8. return o2 - o1;
  9. }
  10. });
  11. set.add(20);
  12. set.add(18);
  13. set.add(23);
  14. set.add(22);
  15. set.add(17);
  16. set.add(24);
  17. set.add(19);
  18. System.out.println(set);
  19. }
  20. 控制台的输出结果为:
  21. [24, 23, 22, 20, 19, 18, 17]

小结

第三章 Map集合

知识点— Map概述

目标

  • 能够说出Map集合的特点

路径

  • 图文演示

讲解

day08【Collections、Set、Map、斗地主排序】 - 图2

  1. Map集合的概述:
  2. Map<K,V>接口概述:也称Map集合,是所有双列集合的顶层父接口,K用来限制键的类型,V用来限制值的类型
  3. Map集合的特点:
  4. 1.Map集合存储元素是以键值对的形式存储,也就是说每一个键值对都有键和值
  5. 2.通过键取值
  6. 3.Map集合中的键不能重复,如果键重复了,那么值就会覆盖
  7. 4.Map集合中的值是可以重复
  8. Map集合的实现类:
  9. HashMap类:键唯一,键值对存取无序, 由哈希表保证键唯一
  10. LinkedHashMap类:键唯一,键值对存取有序,由哈希表保证键唯一,由链表保证键值对存取有序
  11. TreeMap类:键唯一,可以对键值对进行排序

小结

知识点— Map的常用方法

目标

  • 使用Map的常用方法

路径

  • 代码演示

讲解

Map接口中定义了很多方法,常用的如下:

  • public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  • public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  • public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  • public boolean containsKey(Object key):判断该集合中是否有此键
  • public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  • public Collection<V> values() 获取Map集合中所有的值,存储到Collection集合中
  • public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。

Map接口的方法演示

  1. public class Test {
  2. public static void main(String[] args) {
  3. /*
  4. Map<K,V>的常用方法:
  5. - public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  6. - public int size() 获取集合中键值对的个数(Map集合的大小)
  7. - public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  8. - public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  9. - public boolean containsKey(Object key):判断该集合中是否有此键
  10. - public boolean containsValue(Object value) 判断该集合中是否有此值
  11. - public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  12. - public Collection<V> values() 获取Map集合中所有的值,存储到Collection集合中。
  13. - public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中 所有的 键值对对象 的集合(Set集合)。
  14. Entry<K, V>: 一种数据类型,表示键值对对象类型
  15. 由于 Entry<K, V> 是Map接口的成员内部接口,所以表示的时候这么写Map.Entry<K,V>
  16. Entry接口中的方法:
  17. K getKey(); 获取键值对对象的键
  18. V getValue(); 获取键值对对象的值
  19. 键值对: 两个对象
  20. 键值对对象: 一个对象(包装了键值对后的一个对象)
  21. */
  22. Map<String, String> map = new HashMap<>();
  23. // 往集合中添加键值对
  24. map.put("黄晓明", "杨颖");
  25. map.put("文章", "马伊琍");
  26. map.put("谢霆锋", "王菲");
  27. map.put("李亚鹏", "王菲");
  28. // public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中 所有的 键值对对象 的集合(Set集合)。
  29. Set<Map.Entry<String, String>> entrySet = map.entrySet();
  30. System.out.println(entrySet);
  31. System.out.println(entrySet.size());
  32. }
  33. /*
  34. - public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  35. - public Collection<V> values() 获取Map集合中所有的值,存储到Collection集合中。
  36. */
  37. private static void method02() {
  38. // 创建Map集合,限制键的类型为String,限制值的类型为String
  39. Map<String, String> map = new HashMap<>();
  40. // 往集合中添加键值对
  41. map.put("黄晓明", "杨颖");
  42. map.put("文章", "马伊琍");
  43. map.put("谢霆锋", "王菲");
  44. map.put("李亚鹏", "王菲");
  45. // public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  46. Set<String> keys = map.keySet();
  47. System.out.println(keys);// [文章, 谢霆锋, 李亚鹏, 黄晓明]
  48. // public Collection<V> values() 获取Map集合中所有的值,存储到Collection集合中。
  49. Collection<String> values = map.values();
  50. System.out.println(values);// [马伊琍, 王菲, 王菲, 杨颖]
  51. }
  52. /*
  53. - public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  54. - public int size() 获取集合中键值对的个数(Map集合的大小)
  55. - public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  56. - public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  57. - public boolean containsKey(Object key):判断该集合中是否有此键
  58. - public boolean containsValue(Object value) 判断该集合中是否有此值
  59. */
  60. private static void method01() {
  61. // 创建Map集合,限制键的类型为String,限制值的类型为String
  62. Map<String, String> map = new HashMap<>();
  63. // public V put(K key, V value) 把指定的键与指定的值添加到Map集合中。
  64. map.put("黄晓明","杨颖");
  65. String value1 = map.put("文章", "马伊琍");// null
  66. String value2 = map.put("文章", "姚笛");// 马伊琍
  67. map.put("谢霆锋", "王菲");
  68. System.out.println("value1:"+value1);
  69. System.out.println("value2:"+value2);
  70. System.out.println(map);// {文章=姚笛, 谢霆锋=王菲, 黄晓明=杨颖}
  71. // public int size() 获取集合中键值对的个数(Map集合的大小)
  72. System.out.println(map.size());// 3
  73. System.out.println("=================================");
  74. // public V remove(Object key); 根据指定的键,删除集合中对应的键值对
  75. String value3 = map.remove("文章");
  76. System.out.println("value3:"+value3);// 姚笛
  77. System.out.println(map);// {谢霆锋=王菲, 黄晓明=杨颖}
  78. // public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  79. String value4 = map.get("谢霆锋");
  80. System.out.println("value4:"+value4);// 王菲
  81. System.out.println("======================");
  82. // public boolean containKey(Object key):判断该集合中是否有此键
  83. System.out.println(map.containsKey("谢霆锋"));// true
  84. System.out.println(map.containsKey("李亚鹏"));// false
  85. // public boolean containsValue(Object value) 判断该集合中是否有此值
  86. System.out.println(map.containsValue("王菲"));// true
  87. System.out.println(map.containsValue("张柏芝"));// false
  88. }
  89. }

tips:

使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;

若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。

小结

知识点—Map的遍历

目标

  • 使用Map的遍历

路径

  • 方式1:键找值方式
  • 方式2:键值对方式

讲解

方式1:键找值方式

通过元素中的键,获取键所对应的值

分析步骤:

  1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keyset()
  2. 遍历键的Set集合,得到每一个键。
  3. 根据键,获取键所对应的值。方法提示:get(K key)
  1. public class Demo {
  2. public static void main(String[] args) {
  3. // 创建Map集合对象,限制键的类型为String,值的类型为String
  4. Map<String, String> map = new HashMap<>();
  5. // 往map集合中添加键值对
  6. map.put("黄晓明", "杨颖");
  7. map.put("文章", "马伊琍");
  8. map.put("谢霆锋", "王菲");
  9. // 遍历map集合
  10. // 获取集合中所有的键 Set<K> keySet()方法
  11. Set<String> keys = map.keySet();
  12. // 遍历所有的键的集合
  13. for (String key : keys) {
  14. // 在循环中,根据键找值 V get(K key)方法
  15. String value = map.get(key);
  16. System.out.println("键:"+key+",值:"+value);
  17. }
  18. }
  19. }

方式2:键值对方式

  1. Entry<K,V>接口:简称Entry项,表示键值对对象,用来封装Map集合中的键值对
  2. Entry<K,V>接口:是Map接口中的内部接口,在外部使用的时候是这样表示: Map.Entry<K,V>
  3. Map集合中提供了一个方法来获取所有键值对对象:
  4. public Set<Map.Entry<K,V>> entrySet()
  5. 根据键值对对对象获取键和值:
  6. - public K getKey():获取Entry对象中的键。
  7. - public V getValue():获取Entry对象中的值。
  8. Map遍历方式二:根据键值对对象的方式
  9. 1.获取集合中所有键值对对象,以Set集合形式返回。 Set<Map.Entry<K,V>> entrySet()
  10. 2.遍历所有键值对对象的集合,得到每一个键值对(Entry)对象。
  11. 3.在循环中,可以使用键值对对对象获取键和值 getKey()和getValue()
  1. public class Demo {
  2. public static void main(String[] args) {
  3. // 创建Map集合对象,限制键的类型为String,值的类型为String
  4. Map<String, String> map = new HashMap<>();
  5. // 往map集合中添加键值对
  6. map.put("黄晓明", "杨颖");
  7. map.put("文章", "马伊琍");
  8. map.put("谢霆锋", "王菲");
  9. // 获取集合中所有键值对对象 Set<Map.Entry<K,V>> entrySet()
  10. Set<Map.Entry<String, String>> entrySet = map.entrySet();
  11. // 遍历所有键值对对象的集合
  12. for (Map.Entry<String, String> entry : entrySet) {
  13. // 在循环中,可以使用键值对对对象获取键和值 getKey()和getValue()
  14. String key = entry.getKey();
  15. String value = entry.getValue();
  16. System.out.println("键:"+key+",值:"+value);
  17. }
  18. }
  19. }

小结

知识点— HashMap存储自定义类型

目标

  • 使用HashMap存储自定义类型

路径

  • 代码演示

讲解

练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。

注意,学生姓名相同并且年龄相同视为同一名学生。

编写学生类:

  1. public class Student {
  2. /**
  3. * 姓名
  4. */
  5. public String name;
  6. /**
  7. * 年龄
  8. */
  9. public int age;
  10. public Student() {
  11. }
  12. public Student(String name, int age) {
  13. this.name = name;
  14. this.age = age;
  15. }
  16. @Override
  17. public String toString() {
  18. return "Student{" +
  19. "name='" + name + '\'' +
  20. ", age=" + age +
  21. '}';
  22. }
  23. @Override
  24. public boolean equals(Object o) {
  25. if (this == o) return true;
  26. if (o == null || getClass() != o.getClass()) return false;
  27. Student student = (Student) o;
  28. return age == student.age &&
  29. Objects.equals(name, student.name);
  30. }
  31. @Override
  32. public int hashCode() {
  33. return Objects.hash(name, age);
  34. }
  35. }

编写测试类:

  1. public class Demo {
  2. public static void main(String[] args) {
  3. // 创建Map集合,指定键的类型为Student,值的类型为String
  4. HashMap<Student,String> map = new HashMap<>();
  5. // 创建多个学生对象
  6. Student stu1 = new Student("张三", 18);
  7. Student stu2 = new Student("李四", 38);
  8. Student stu3 = new Student("王五", 28);
  9. Student stu4 = new Student("张三", 18);
  10. // 把学生对象作为键,家庭地址作为值,存储到map集合中
  11. map.put(stu1,"北京");
  12. map.put(stu2,"上海");
  13. map.put(stu3,"深圳");
  14. map.put(stu4,"广州");
  15. // 打印map集合
  16. System.out.println(map);
  17. System.out.println(map.size());// 3
  18. }
  19. }
  • 当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。
  • 如果要保证map中存放的key和取出的顺序一致,可以使用java.util.LinkedHashMap集合来存放。

小结

知识点—LinkedHashMap介绍

目标

  • 我们知道HashMap保证成对元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,那么我们要保证有序,还要速度快怎么办呢?

路径

  • LinkedHashMap

讲解

  • 通过链表结构可以保证元素的存取顺序一致;
  • 通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
  1. public class Test {
  2. public static void main(String[] args) {
  3. /*
  4. LinkedHashMap介绍:
  5. LinkedHashMap集合(类): 元素无索引,键唯一,键值对元素存取有序
  6. 存储数据采用的是哈希表+链表结构
  7. 由哈希表保证键唯一,由链表保证键值对元素存取有序
  8. 如果键是自定义类型的类,为了保证键唯一,就得重写hashCode()和equals()方法
  9. */
  10. // 创建LinkedHashMap集合,限制键的类型为String类型,限制值的类型为String类型
  11. LinkedHashMap<String, String> map = new LinkedHashMap<>();
  12. //HashMap<String, String> map = new HashMap<>();
  13. // 往集合中添加键值对
  14. map.put("黄晓明", "杨颖");
  15. map.put("文章", "马伊琍");
  16. map.put("谢霆锋", "王菲");
  17. map.put("李亚鹏", "王菲");
  18. map.put("文章", "姚笛");
  19. // 打印集合
  20. System.out.println(map);
  21. }
  22. }

小结

知识点—TreeMap集合

目标

  • 使用TreeMap集合

路径

  • TreeMap介绍
  • 构造方法

讲解

TreeMap介绍

TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的进行排序,排序方式有两种:自然排序比较器排序;到时使用的是哪种排序,取决于我们在创建对象的时候所使用的构造方法;

构造方法

  1. public TreeMap() 使用自然排序
  2. public TreeMap(Comparator<? super K> comparator) 通过比较器指定规则排序

案例演示

  1. public class Test {
  2. public static void main(String[] args) {
  3. /*
  4. TreeMap集合:
  5. TreeMap集合(类):元素无索引,键唯一,键值对元素根据键排序
  6. 存储数据采用的是红黑树结构,由红黑树结构保证键唯一
  7. 构造方法:
  8. TreeMap(); 按照键的默认排序规则对键值对进行排序
  9. 要求: 集合中键所属的类要实现Comparable接口,重写compareTo方法,在该方法中写好默认的排序规则
  10. TreeMap(Comparator<? super K> comparator):按照键的指定排序规则对键值对进行排序
  11. 键为自定义类型的类,课后自己去玩玩
  12. */
  13. // 按照键的默认规则排序:
  14. // 创建TreeMap集合,限制键的类型为Integer,限制值的类型为String
  15. TreeMap<Integer, String> map = new TreeMap<>();
  16. // 往集合中添加键值对
  17. map.put(300, "黄晓明");
  18. map.put(100, "刘德华");
  19. map.put(200, "黎明");
  20. map.put(500, "张学友");
  21. map.put(400, "郭富城");
  22. // 打印集合
  23. System.out.println(map);// {100=刘德华, 200=黎明, 300=黄晓明, 400=郭富城, 500=张学友}
  24. System.out.println("+++++++++++++++++++++++++++++++++");
  25. // 按照键的指定规则排序:
  26. // 创建TreeMap集合,限制键的类型为Integer,限制值的类型为String
  27. TreeMap<Integer, String> map2 = new TreeMap<>(new Comparator<Integer>() {
  28. @Override
  29. public int compare(Integer o1, Integer o2) {
  30. // 指定规则: 前减后 升序 后减前 降序
  31. return o2 - o1;
  32. }
  33. });
  34. // 往集合中添加键值对
  35. map2.put(300, "黄晓明");
  36. map2.put(100, "刘德华");
  37. map2.put(200, "黎明");
  38. map2.put(500, "张学友");
  39. map2.put(400, "郭富城");
  40. System.out.println(map2);// {500=张学友, 400=郭富城, 300=黄晓明, 200=黎明, 100=刘德华}
  41. }
  42. }

小结

案例— Map集合练习

需求

  • 输入一个字符串,获取该字符串中每个字符出现次数。

分析

  • 获取一个字符串对象
  • 创建一个Map集合,键代表字符,值代表次数。
  • 遍历字符串得到每个字符。
  • 判断Map中是否有该键。
  • 如果没有,第一次出现,存储次数为1;如果有,则说明已经出现过,获取到对应的值进行++,再次存储。
  • 打印最终结果

实现

方法介绍

public boolean containKey(Object key):判断该集合中是否有此键。

代码:

  1. public class Test {
  2. public static void main(String[] args) {
  3. /*
  4. Map集合练习:
  5. 需求:输入一个字符串中每个字符出现次
  6. */
  7. // 分析:
  8. // 1.创建Map集合,限制键的类型为Character,值的类型为Integer
  9. Map<Character, Integer> map = new HashMap<>();
  10. // 2.创建Scanner对象
  11. Scanner sc = new Scanner(System.in);
  12. // 3.获取键盘录入的字符串
  13. System.out.println("请输入一个字符串:");
  14. String str = sc.nextLine();
  15. // 4.遍历字符串的每一个字符
  16. for (int i = 0; i < str.length(); i++) {
  17. // 5.在循环中,获取字符串的字符,该字符作为map集合的键
  18. char cKey = str.charAt(i);
  19. // 6.在循环中,判断遍历出来的字符在map集合中是否存在该键
  20. boolean flag = map.containsKey(cKey);
  21. // 7.在循环中,如果不存在,字符作为键,值为1,存储到map集合中
  22. // 8.在循环中,如果存在,获取该字符键对应的值,进行+1后作为新的值
  23. // 然后在重新存储到集合中
  24. if (flag == false){
  25. map.put(cKey,1);
  26. }else{
  27. Integer oldValue = map.get(cKey);// 获取该字符键对应的值
  28. Integer newValue = oldValue + 1;// +1
  29. map.put(cKey,newValue);
  30. }
  31. }
  32. // 9.最后打印map集合
  33. System.out.println(map);
  34. }
  35. }

小结

第四章 集合的嵌套

  • 总述:任何集合内部都可以存储其它任何集合

知识点—集合的嵌套

目标

  • 理解集合的嵌套

路径

  • List嵌套List
  • List嵌套Map
  • Map嵌套Map

讲解

List嵌套List

  1. public class Test1 {
  2. public static void main(String[] args) {
  3. /*
  4. 集合的嵌套:
  5. - List嵌套List
  6. - List嵌套Map
  7. - Map嵌套Map
  8. 结论:任何集合内部都可以存储其它任何集合
  9. */
  10. // List嵌套List
  11. // 创建一个List集合,限制元素类型为String
  12. List<String> list1 = new ArrayList<>();
  13. // 往集合中添加元素
  14. list1.add("王宝强");
  15. list1.add("贾乃亮");
  16. list1.add("陈羽凡");
  17. // 创建一个List集合,限制元素类型为String
  18. List<String> list2 = new ArrayList<>();
  19. // 往集合中添加元素
  20. list2.add("马蓉");
  21. list2.add("李小璐");
  22. list2.add("白百何");
  23. // 创建一个List集合,限制元素类型为List集合 (List集合中的元素是List集合)
  24. List<List<String>> list = new ArrayList<>();
  25. list.add(list1);
  26. list.add(list2);
  27. // 遍历
  28. for (List<String> e : list) {
  29. for (String name : e) {
  30. System.out.println(name);
  31. }
  32. System.out.println("=============");
  33. }
  34. System.out.println(list);
  35. }
  36. }

List嵌套Map

  1. public class Test2 {
  2. public static void main(String[] args) {
  3. /*
  4. List嵌套Map:
  5. */
  6. // 创建Map集合对象
  7. Map<String,String> map1 = new HashMap<>();
  8. map1.put("it001","迪丽热巴");
  9. map1.put("it002","古力娜扎");
  10. // 创建Map集合对象
  11. Map<String,String> map2 = new HashMap<>();
  12. map2.put("heima001","蔡徐坤");
  13. map2.put("heima002","李易峰");
  14. // 创建List集合,用来存储以上2个map集合
  15. List<Map<String,String>> list = new ArrayList<>();
  16. list.add(map1);
  17. list.add(map2);
  18. System.out.println(list.size()); // 2
  19. for (Map<String, String> map : list) {
  20. // 遍历获取出来的map集合对象
  21. Set<String> keys = map.keySet();// 获取map集合所有的键
  22. // 根据键找值
  23. for (String key : keys) {
  24. System.out.println(key + ","+ map.get(key));
  25. }
  26. }
  27. }
  28. }

Map嵌套Map

  1. public class Test3 {
  2. public static void main(String[] args) {
  3. /*
  4. Map嵌套Map:
  5. */
  6. // 创建Map集合对象
  7. Map<String,String> map1 = new HashMap<>();
  8. map1.put("it001","迪丽热巴");
  9. map1.put("it002","古力娜扎");
  10. // 创建Map集合对象
  11. Map<String,String> map2 = new HashMap<>();
  12. map2.put("heima001","蔡徐坤");
  13. map2.put("heima002","李易峰");
  14. // 创建Map集合,把以上2个Map集合作为值存储到这个map集合中
  15. Map<String, Map<String, String>> map = new HashMap<>();
  16. map.put("传智博客",map1);
  17. map.put("黑马程序员",map2);
  18. System.out.println(map.size());// 2
  19. // 获取map集合中的所有键
  20. Set<String> keys = map.keySet();
  21. // 遍历所有的键
  22. for (String key : keys) {
  23. // 根据键找值
  24. Map<String, String> value = map.get(key);
  25. // 遍历value这个Map集合
  26. Set<String> keySet = value.keySet();
  27. for (String k : keySet) {
  28. String v = value.get(k);
  29. System.out.println(k+","+v);
  30. }
  31. }
  32. }
  33. }

小结

第五章 模拟斗地主洗牌发牌

需求

按照斗地主的规则,完成洗牌发牌的动作。

day08【Collections、Set、Map、斗地主排序】 - 图3

具体规则:

  1. 组装54张扑克牌
  2. 54张牌顺序打乱
  3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
  4. 查看三人各自手中的牌(按照牌的大小排序)、底牌

规则:手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3

分析

1.准备牌:

完成数字与纸牌的映射关系:

使用双列Map(HashMap)集合,完成一个数字与字符串纸牌的对应关系(相当于一个字典)。

2.洗牌:

通过数字完成洗牌发牌

3.发牌:

将每个人以及底牌设计为ArrayList,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。

存放的过程中要求数字大小与斗地主规则的大小对应。

将代表不同纸牌的数字分配给不同的玩家与底牌。

4.看牌:

通过Map集合找到对应字符展示。

通过查询纸牌与数字的对应关系,由数字转成纸牌字符串再进行展示。

day08【Collections、Set、Map、斗地主排序】 - 图4

实现

  1. package com.itheima04;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.HashMap;
  5. public class Test {
  6. public static void main(String[] args) {
  7. /*
  8. 模拟斗地主洗牌发牌:
  9. 需求
  10. 按照斗地主的规则,完成洗牌发牌的动作。
  11. 具体规则:
  12. 1. 组装54张扑克牌
  13. 2. 54张牌顺序打乱
  14. 3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
  15. 4. 查看三人各自手中的牌(按照牌的大小排序)、底牌
  16. 规则:手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3
  17. */
  18. // 造牌
  19. // 1.创建Map集合对象,限制键的类型为Integer,值的类型为String
  20. HashMap<Integer, String> pokeBox = new HashMap<>();
  21. // 2.创建一个List集合,表示花色集合,
  22. ArrayList<String> colors = new ArrayList<>();
  23. // 3.创建一个List集合,表示牌面值集合
  24. ArrayList<String> numbers = new ArrayList<>();
  25. // 4.往花色集合中存储4个花色
  26. Collections.addAll(colors, "♥", "♦", "♠", "♣");
  27. // 5.往牌面值集合中存储13个牌面值
  28. Collections.addAll(numbers, "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3");
  29. // 6.定义一个int类型的变量,表示牌的编号,初始值为0
  30. int id = 0;
  31. // 7.往map集合中添加大王,编号为0,添加完后编号自增1
  32. pokeBox.put(id++, "大王");
  33. // 8.往map集合中添加小王,编号为1,添加完后编号自增1
  34. pokeBox.put(id++, "小王");
  35. // 9.牌面值的集合和花色集合循环嵌套遍历,注意牌面值集合作为外层循环,花色集合作为内层循环
  36. for (String number : numbers) {
  37. for (String color : colors) {
  38. // 10.在循环中,遍历出来的牌面值和花色组成一张扑克牌
  39. String pai = color + number;
  40. // 11.在循环中,编号作为键,扑克牌作为值存储到map集合中,每存储一张牌后,编号自增1
  41. pokeBox.put(id++,pai);
  42. }
  43. }
  44. System.out.println(pokeBox.size());
  45. System.out.println(pokeBox);
  46. //2.洗牌 :--->洗牌的编号
  47. //2.1 获取所有牌的编号,返回的是所有编号的Set集合
  48. Set<Integer> keySet = pokeBox.keySet();
  49. //2.2 创建ArrayList集合,用来存储所有的牌编号
  50. ArrayList<Integer> idList = new ArrayList<>();
  51. //2.3 把keySet集合中存储的所有牌编号,存储到这个新的ArrayList集合中
  52. idList.addAll(keySet);
  53. //2.4 使用Collections.shuffle方法对新的ArrayList集合中的元素打乱顺序
  54. Collections.shuffle(idList);
  55. System.out.println("打乱顺序后的牌编号:"+idList.size());// 54
  56. System.out.println("打乱顺序后的牌编号:"+idList);
  57. // 3.发牌-->发牌的编号--->对牌的编号进行从小到大排序---->再根据排好序的编号去map集合中获取牌
  58. // 3.1 创建4个List集合,分别用来存储玩家一,玩家二,玩家三,底牌得到的牌编号
  59. ArrayList<Integer> play1Id = new ArrayList<>();
  60. ArrayList<Integer> play2Id = new ArrayList<>();
  61. ArrayList<Integer> play3Id = new ArrayList<>();
  62. ArrayList<Integer> diPaiId = new ArrayList<>();
  63. // 3.2 循环把打乱顺序的牌编号,按照规律依次发给玩家一,玩家二,玩家三,底牌
  64. for (int i = 0; i < idList.size(); i++) {
  65. // 获取牌编号
  66. Integer paiId = idList.get(i);
  67. // 三人交替摸牌
  68. if (i >= 51){
  69. diPaiId.add(paiId);
  70. }else if (i%3==0){
  71. play1Id.add(paiId);
  72. }else if (i%3==1){
  73. play2Id.add(paiId);
  74. }else if (i%3==2){
  75. play3Id.add(paiId);
  76. }
  77. }
  78. // 3.3 对获取到的牌编号进行从小到大排序
  79. Collections.sort(play1Id);
  80. Collections.sort(play2Id);
  81. Collections.sort(play3Id);
  82. Collections.sort(diPaiId);
  83. // 3.4 根据排好序的牌编号去map集合中获取牌
  84. // 遍历玩家一的牌编号
  85. System.out.print("玩家一的牌:");
  86. for (Integer paiId : play1Id) {// 1,2,3,4,5
  87. String pai = pokeBox.get(paiId);
  88. System.out.print(pai+" ");
  89. }
  90. System.out.println();
  91. // 遍历玩家二的牌编号
  92. System.out.print("玩家二的牌:");
  93. for (Integer paiId : play2Id) {
  94. String pai = pokeBox.get(paiId);
  95. System.out.print(pai+" ");
  96. }
  97. System.out.println();
  98. // 遍历玩家三的牌编号
  99. System.out.print("玩家三的牌:");
  100. for (Integer paiId : play3Id) {
  101. String pai = pokeBox.get(paiId);
  102. System.out.print(pai+" ");
  103. }
  104. System.out.println();
  105. // 遍历底牌的牌编号
  106. System.out.print("底牌的牌:");
  107. for (Integer paiId : diPaiId) {
  108. String pai = pokeBox.get(paiId);
  109. System.out.print(pai+" ");
  110. }
  111. }
  112. }

小结

总结

  1. - 能够使用集合工具类
  2. Collections工具类:
  3. - public static void shuffle(List<?> list):打乱集合顺序。
  4. - public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
  5. - public static <T> void sort(List<T> listComparator<? super T> com ):将集合中元素按照指定规则排序。
  6. - public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。
  7. - 能够使用Comparator比较器进行排序
  8. 创建Comparator接口的匿名内部类,重写compare方法,在comapre方法中定义排序规则
  9. 前减后 升序
  10. 后减前 降序
  11. - 能够使用可变参数
  12. 使用场景; 如果一个方法需要接收多个相同类型的参数,就可以使用可变参数
  13. 格式: 修饰符 返回值类型 方法名(数据类型... 变量名){}
  14. 注意: 1.一个方法只能有一个可变参数,2.如果方法有多个参数,可变参数需要放在最后面
  15. - 能够说出Set集合的特点
  16. 元素唯一,元素存取无序,元素无索引
  17. - 能够说出哈希表的特点
  18. 哈希表:保证元素唯一,依赖hashCodeequals方法
  19. 哈希表结构:
  20. jdk8以前: 数组+链表
  21. jdk8以后: 数组+链表+红黑树
  22. - 使用HashSet集合存储自定义元素
  23. 重写hashCodeequals方法
  24. - 能够说出Map集合特点
  25. 键唯一,键重复,就会覆盖原来的值
  26. 以键值对的形式存储数据
  27. 根据键找值
  28. - 使用Map集合添加方法保存数据
  29. - public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  30. - public V remove(Object key): 把指定的键 所对应的键值对元素 Map集合中删除,返回被删除元素的值。
  31. - public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  32. - public boolean containsKey(Object key):判断该集合中是否有此键
  33. - public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  34. - public Collection<V> values() 获取Map集合中所有的值,存储到Collection集合中
  35. - public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
  36. - 使用”键找值”的方式遍历Map集合
  37. 1.获取所有的键
  38. 2.遍历所有的键
  39. 3.根据键找值
  40. - 使用”键值对”的方式遍历Map集合
  41. 1.获取所有的键值对对象
  42. 2.遍历所有的键值对对象
  43. 3.使用键值对对象获取键和值
  44. - 能够使用HashMap存储自定义键值对的数据
  45. 键所属的类要重写hashCodeequals方法
  46. - 能够完成斗地主洗牌发牌案例
  47. 造牌--洗牌--发牌