day08【Collections、Set、Map、斗地主排序】 今日内容
Collections工具类
Set集合
Map集合
集合的嵌套
综合案例
教学目标
第一章 Collections类 知识点– 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> ):将集合中元素按照指定规则排序。
shuffle方法代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.itheima.demo1_Collections常用功能;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class Test1_shuffle { public static void main (String[] args) { List<Integer> list = new ArrayList<>(); list.add(300 ); list.add(100 ); list.add(200 ); list.add(500 ); list.add(400 ); System.out.println("打乱顺序之前的集合:" +list); Collections.shuffle(list); System.out.println("打乱顺序之后的集合:" +list); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 package com.itheima.demo1_Collections常用功能;public class Student implements Comparable <Student > { int age; public Student (int age) { this .age = age; } @Override public String toString () { return "Student{" + "age=" + age + '}' ; } @Override public int compareTo (Student o) { return this .age - o.age; } }package com.itheima.demo1_Collections常用功能;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class Test2_sort { public static void main (String[] args) { List<Integer> list = new ArrayList<>(); list.add(300 ); list.add(100 ); list.add(200 ); list.add(500 ); list.add(400 ); System.out.println("排序之前的集合:" +list); Collections.sort(list); System.out.println("排序之后的集合:" +list); System.out.println("=========================================" ); List<Student> list1 = new ArrayList<>(); Student stu1 = new Student(19 ); Student stu2 = new Student(18 ); Student stu3 = new Student(20 ); Student stu4 = new Student(17 ); list1.add(stu1); list1.add(stu2); list1.add(stu3); list1.add(stu4); System.out.println("排序之前的集合:" +list1); Collections.sort(list1); System.out.println("排序之后的集合:" +list1); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 package com.itheima.demo1_Collections常用功能;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;public class Test3_sort { public static void main (String[] args) { List<Integer> list = new ArrayList<>(); list.add(300 ); list.add(100 ); list.add(200 ); list.add(500 ); list.add(400 ); System.out.println("排序之前的集合:" + list); Collections.sort(list, new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); System.out.println("排序之后的集合:" + list); Collections.sort(list, new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o1 - o2; } }); System.out.println("排序之后的集合:" + list); System.out.println("=======================================" ); List<Student> list1 = new ArrayList<>(); Student stu1 = new Student(19 ); Student stu2 = new Student(18 ); Student stu3 = new Student(20 ); Student stu4 = new Student(17 ); list1.add(stu1); list1.add(stu2); list1.add(stu3); list1.add(stu4); System.out.println("排序之前的集合:" + list1); Collections.sort(list1, new Comparator<Student>() { @Override public int compare (Student o1, Student o2) { return o2.age - o1.age; } }); System.out.println("排序之后的集合:" + list1); Collections.sort(list1, new Comparator<Student>() { @Override public int compare (Student o1, Student o2) { return o1.age - o2.age; } }); System.out.println("排序之后的集合:" + list1); } }
小结 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - public static void shuffle (List<?> list) :打乱集合顺序。- public static <T> void sort (List<T> list) :将集合中元素按照默认规则排序。 默认规则: 事先写好的排序规则 在哪里写好排序规则?---->集合元素所属的类中写好排序规则(通过实现Comparable接口,重写compareTo(T o) 方法写好排序规则) 排序规则: 前减后 升序 后减前 降序 前: this 后:参数 - public static <T> void sort (List<T> list,Comparator<? super T> com) :将集合中元素按照指定规则排序。 指定规则排序: 通过Comparator参数来指定 通过传入Comparator接口的匿名内部类,重写compare (T o1,T o2) 方法,在该方法中指定排序规则 排序规则: 前减后 升序 后减前 降序 前: 第一个参数 后:第二个参数
知识点– 可变参数 目标
路径
可变参数的使用
注意事项
应用场景: Collections
讲解 可变参数的使用 在JDK1.5 之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化.
格式:
1 修饰符 返回值类型 方法名(参数类型... 形参名){ }
代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package com.itheima.demo2_可变参数;public class Test1 { public static void main (String[] args) { method3(10 ,20 ,30 ,40 ,50 ); } public static void method3 (int ... nums) { for (int i = 0 ; i < nums.length; i++) { System.out.println(nums[i]); } } public static void method2 (int [] arr) { for (int i = 0 ; i < arr.length; i++) { System.out.println(arr[i]); } } public static void method1 (int num1,int num2,int num3,int num4,int num5) { } }
注意事项 1.一个方法只能有一个可变参数
2.如果方法中有多个参数,可变参数要放到最后。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.itheima.demo2_可变参数;public class Test2 { public static void main (String[] args) { method3("itheima" ,10 ,20 ); } public static void method3 (String str,int ... nums) { } }
应用场景: Collections 在Collections中也提供了添加一些元素方法:
public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中添加一些元素。
代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.itheima.demo2_可变参数;import java.util.ArrayList;import java.util.Collections;public class Test3 { public static void main (String[] args) { ArrayList<String> list = new ArrayList<>(); Collections.addAll(list,"2" ,"A" ,"K" ,"Q" ,"J" ,"10" ,"9" ,"8" ,"7" ,"6" ,"5" ,"4" ,"3" ); System.out.println(list); } }
小结 略
第二章 Set接口 知识点–Set接口介绍 目标
路径
讲解 1 2 3 4 5 6 7 8 Set接口:也称Set集合,但凡是实现了Set接口的类都叫做Set集合 特点: 元素无索引,元素不可重复(唯一) HashSet集合: 实现类--元素存取无序 LinkedHashSet集合:实现类--元素存取有序 TreeSet集合:实现类--> 对元素进行排序 注意:1. Set集合没有特殊的方法,都是使用Collection接口的方法 2. Set集合没有索引,所以遍历元素的方式就只有: 增强for 循环,或者迭代器
小结 略
知识点–HashSet集合 目标
路径
讲解 java.util.HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不能保证不一致)。
我们先来使用一下Set集合存储,看下现象,再进行原理的讲解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Test { public static void main (String[] args) { HashSet<String> set = new HashSet<>(); set.add("nba" ); set.add("cba" ); set.add("bac" ); set.add("abc" ); set.add("nba" ); System.out.println(set); } }
小结 略
知识点–HashSet集合存储数据的结构(哈希表) 目标
路径
讲解 哈希表底层结构 在JDK1.8 之前,哈希表底层采用数组+链表实现,即使用数组处理冲突,同一hash值的链表都存储在一个数组里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示。
HashSet保证元素唯一原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -HashSet集合存储数据的结构---哈希表结构 哈希表结构: jdk8以前: 数组+链表 jdk8以后: 数组+链表+红黑树 链表元素个数没有超过8 : 数组+链表 链表元素个数超过8 : 数组+链表+红黑树 -HashSet集合保证元素唯一的原理--依赖hashCode()和equals()方法 1. 当存储元素的时候,就会调用该元素的hashCode()方法计算该元素的哈希值 2. 判断该哈希值对应的位置上,是否有元素: 3. 如果该哈希值对应的位置上,没有元素,就直接存储 4. 如果该哈希值对应的位置上,有元素,说明产生了哈希冲突 5. 产生了哈希冲突,就得调用该元素的equals方法,与该位置上的所有元素进行一一比较: 如果比较的时候,有任意一个元素与该元素相同,那么就不存储 如果比较完了,没有一个元素与该元素相同,那么就直接存储 补充: Object类: hashCode()和equals()方法; hashCode():Object类中的hashCode()方法是根据地址值计算哈希值 equals方法():Object类中的equals()方法是比较地址值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Demo { public static void main (String[] args) { HashSet<String> set = new HashSet<>(); set.add("nba" ); set.add("cba" ); set.add("bac" ); set.add("abc" ); set.add("nba" ); for (String e : set) { System.out.println(e); } System.out.println("nba" .hashCode()); System.out.println("cba" .hashCode()); System.out.println("bac" .hashCode()); System.out.println("abc" .hashCode()); } }
小结 略
扩展 HashSet的源码分析 3.4.1 HashSet的成员属性及构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class HashSet <E > extends AbstractSet <E > implements Set <E >, Cloneable , java .io .Serializable { private transient HashMap<E,Object> map; private static final Object PRESENT = new Object(); public HashSet () { map = new HashMap<>(); } }
通过构造方法可以看出,HashSet构造时,实际上是构造一个HashMap
3.4.2 HashSet的add方法源码解析 1 2 3 4 5 6 7 public class HashSet { public boolean add (E e) { return map.put(e, PRESENT)==null ; } }
3.4.3 HashMap的put方法源码解析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class HashMap { public V put (K key, V value) { return putVal(hash(key), key, value, false , true ); } static final int hash (Object key) { int h; return (key == null ) ? 0 : (h = key.hashCode()) ^ (h >>> 16 ); } final V putVal (int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0 ) n = (tab = resize()).length; if ((p = tab[i = (n - 1 ) & hash]) == null ) tab[i] = newNode(hash, key, value, null ); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this , tab, hash, key, value); else { for (int binCount = 0 ; ; ++binCount) { if ((e = p.next) == null ) { p.next = newNode(hash, key, value, null ); if (binCount >= TREEIFY_THRESHOLD - 1 ) treeifyBin(tab, hash); break ; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break ; p = e; } } if (e != null ) { V oldValue = e.value; if (!onlyIfAbsent || oldValue == null ) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null ; } }
知识点– HashSet存储自定义类型元素 1.目标
2.路径
3.讲解 给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class Person { public String name; public int age; public Person () { } public Person (String name, int age) { this .name = name; this .age = age; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode () { return Objects.hash(name, age); } }
创建测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class Demo { public static void main (String[] args) { Person p1 = new Person("张三" , 18 ); Person p2 = new Person("李四" , 38 ); Person p3 = new Person("王五" , 28 ); Person p4 = new Person("张三" , 18 ); HashSet<Person> set = new HashSet<>(); set.add(p1); set.add(p2); set.add(p3); set.add(p4); for (Person p : set) { System.out.println(p); } System.out.println(p1.hashCode()); System.out.println(p2.hashCode()); System.out.println(p3.hashCode()); System.out.println(p4.hashCode()); } }
小结 略
知识点– LinkedHashSet 目标
使用LinkedHashSet保证元素怎么存就怎么取,即存取有序
路径
讲解 我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?
在HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。
演示代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.itheima.demo5_LinkedHashSet;import java.util.HashSet;import java.util.LinkedHashSet;public class Test { public static void main (String[] args) { LinkedHashSet<Integer> set = new LinkedHashSet<>(); set.add(300 ); set.add(100 ); set.add(200 ); set.add(500 ); set.add(400 ); set.add(400 ); System.out.println(set); } }
小结 略
知识点– TreeSet集合 目标
知道使用TreeSet集合的特点并能够使用TreeSet集合
路径
讲解 特点 TreeSet集合是Set接口的一个实现类,底层依赖于TreeMap,是一种基于红黑树 的实现,其特点为:
元素唯一
元素没有索引
使用元素的自然顺序 对元素进行排序,或者根据创建 TreeSet 时提供的 Comparator 比较器 进行排序,具体取决于使用的构造方法:
1 2 public TreeSet () : 根据其元素的自然排序进行排序public TreeSet (Comparator<E> comparator) : 根据指定的比较器进行排序
演示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 package com.itheima.demo6_TreeSet集合;import java.util.Comparator;import java.util.LinkedHashSet;import java.util.TreeSet;public class Test { public static void main (String[] args) { TreeSet<Integer> set = new TreeSet<>(); set.add(300 ); set.add(100 ); set.add(200 ); set.add(500 ); set.add(400 ); set.add(400 ); System.out.println(set); System.out.println("===========================================" ); TreeSet<Integer> set1 = new TreeSet<>(new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); set1.add(300 ); set1.add(100 ); set1.add(200 ); set1.add(500 ); set1.add(400 ); set1.add(400 ); System.out.println(set1); System.out.println("===========================================" ); TreeSet<Integer> set2 = new TreeSet<>(new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o1 - o2; } }); set2.add(300 ); set2.add(100 ); set2.add(200 ); set2.add(500 ); set2.add(400 ); set2.add(400 ); System.out.println(set2); } }
小结 略
第三章 Map集合 知识点– Map概述 目标
路径
讲解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Map<K,V>集合的特点: K用来限制键的类型,V用来限制值的类型 1. Map集合存储元素是以键值对的形式存储,每一个键值对都有键和值 2. Map集合的键是唯一,值可以重复,如果键重复了,那么值就会被覆盖 3. 根据键取值 Map集合子类: - HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。 由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。 - LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。 通过链表结构可以保证键值对的存取顺序一致; 通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。 - TreeMap<K,V>: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 Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
Map接口的方法演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 package com.itheima.demo7_Map的常用方法;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Set;public class Test { public static void main (String[] args) { Map<String, String> map = new HashMap<>(); map.put("黄晓明" , "杨颖" ); map.put("文章" , "马伊琍" ); map.put("谢霆锋" , "王菲" ); System.out.println(map); String v1 = map.put("文章" , "姚笛" ); System.out.println("v1:" +v1); System.out.println(map); String v2 = map.put("李亚鹏" , "王菲" ); System.out.println("v2:" +v2); System.out.println(map); String v3 = map.remove("文章" ); System.out.println("被删除键值对的值:" +v3); System.out.println(map); String value = map.get("黄晓明" ); System.out.println("value:" +value); System.out.println(map.containsKey("黄晓明" )); System.out.println(map.containsKey("文章" )); System.out.println(map.containsValue("杨颖" )); System.out.println(map.containsValue("马伊琍" )); Set<String> keys = map.keySet(); System.out.println("keys:" +keys); Collection<String> values = map.values(); System.out.println("values:" +values); Set<Map.Entry<String, String>> set = map.entrySet(); System.out.println(set); } }
tips:
使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
小结 略
知识点–Map的遍历 目标
路径
讲解 方式1:键找值方式 通过元素中的键,获取键所对应的值
分析步骤:
获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keyset()
遍历键的Set集合,得到每一个键。
根据键,获取键所对应的值。方法提示:get(K key)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Demo { public static void main (String[] args) { Map<String, String> map = new HashMap<>(); map.put("黄晓明" , "杨颖" ); map.put("文章" , "马伊琍" ); map.put("谢霆锋" , "王菲" ); Set<String> keys = map.keySet(); for (String key : keys) { String value = map.get(key); System.out.println("键:" +key+",值:" +value); } } }
方式2:键值对方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Entry < K , V > 接口: 简称Entry 项, 表示键值对对象, 用来封装Map 集合中的键值对Entry < K , V > 接口: 是Map 接口中的内部接口, 在外部使用的时候是这样表示: Map . Entry < K , V > Map 集合中提供了一个方法来获取所有键值对对象: public Set < Map . Entry < K , V >> entrySet ( ) 根据键值对对对象获取键和值: - public K getKey ( ) :获取Entry 对象中的键。 - public V getValue ( ) :获取Entry 对象中的值。Map 遍历方式二: 根据键值对对象的方式 1. 获取集合中所有键值对对象,以Set 集合形式返回。 Set < Map . Entry < K , V >> entrySet ( ) 2. 遍历所有键值对对象的集合,得到每一个键值对( Entry ) 对象。 3. 在循环中, 可以使用键值对对对象获取键和值 getKey ( ) 和getValue ( )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Demo { public static void main (String[] args) { Map<String, String> map = new HashMap<>(); map.put("黄晓明" , "杨颖" ); map.put("文章" , "马伊琍" ); map.put("谢霆锋" , "王菲" ); Set<Map.Entry<String, String>> entrySet = map.entrySet(); for (Map.Entry<String, String> entry : entrySet) { String key = entry.getKey(); String value = entry.getValue(); System.out.println("键:" +key+",值:" +value); } } }
小结 略
知识点– HashMap存储自定义类型 目标
路径
讲解 练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。
注意,学生姓名相同并且年龄相同视为同一名学生。
编写学生类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class Student { public String name; public int age; public Student () { } public Student (String name, int age) { this .name = name; this .age = age; } @Override public String toString () { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}' ; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); } @Override public int hashCode () { return Objects.hash(name, age); } }
编写测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Demo { public static void main (String[] args) { HashMap<Student,String> map = new HashMap<>(); Student stu1 = new Student("张三" , 18 ); Student stu2 = new Student("李四" , 38 ); Student stu3 = new Student("王五" , 28 ); Student stu4 = new Student("张三" , 18 ); map.put(stu1,"北京" ); map.put(stu2,"上海" ); map.put(stu3,"深圳" ); map.put(stu4,"广州" ); System.out.println(map); System.out.println(map.size()); } }
当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。
如果要保证map中存放的key和取出的顺序一致,可以使用java.util.LinkedHashMap集合来存放。
小结 略
知识点–LinkedHashMap介绍 目标
我们知道HashMap保证成对元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,那么我们要保证有序,还要速度快怎么办呢?
路径
讲解
通过链表结构可以保证元素的存取顺序一致;
通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.itheima.demo10_LinkedHashMap;import java.util.LinkedHashMap;public class Test { public static void main (String[] args) { LinkedHashMap<Integer, String> map = new LinkedHashMap<>(); map.put(300 , "深圳" ); map.put(100 , "北京" ); map.put(200 , "广州" ); map.put(500 , "上海" ); map.put(400 , "武汉" ); map.put(400 , "深圳" ); System.out.println(map); } }
小结 略
知识点–TreeMap集合 目标
路径
讲解 TreeMap介绍 TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的**键** 进行排序,排序方式有两种:自然排序 和比较器排序 ;到时使用的是哪种排序,取决于我们在创建对象的时候所使用的构造方法;
构造方法 1 2 public TreeMap () 使用自然排序public TreeMap (Comparator<? super K> comparator) 通过比较器指定规则排序
案例演示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.itheima.demo11_TreeMap集合;import java.util.Comparator;import java.util.LinkedHashMap;import java.util.TreeMap;public class Test { public static void main (String[] args) { TreeMap<Integer, String> map = new TreeMap<>(); map.put(300 , "深圳" ); map.put(100 , "北京" ); map.put(200 , "广州" ); map.put(500 , "上海" ); map.put(400 , "武汉" ); map.put(400 , "深圳" ); System.out.println(map); System.out.println("+=================================" ); TreeMap<Integer, String> map1 = new TreeMap<>(new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); map1.put(300 , "深圳" ); map1.put(100 , "北京" ); map1.put(200 , "广州" ); map1.put(500 , "上海" ); map1.put(400 , "武汉" ); map1.put(400 , "深圳" ); System.out.println(map1); } }
小结 略
案例– Map集合练习 需求
分析
获取一个字符串对象
创建一个Map集合,键代表字符,值代表次数。
遍历字符串得到每个字符。
判断Map中是否有该键。
如果没有,第一次出现,存储次数为1;如果有,则说明已经出现过,获取到对应的值进行++,再次存储。
打印最终结果
实现 方法介绍
public boolean containKey(Object key):判断该集合中是否有此键。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package com.itheima.demo12_Map集合练习;import java.util.HashMap;import java.util.Scanner;public class Test { public static void main (String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串:" ); String s = sc.nextLine(); HashMap<Character, Integer> map = new HashMap<>(); for (int i = 0 ; i < s.length(); i++) { char c = s.charAt(i); if (map.containsKey(c)) { Integer value = map.get(c); value++; map.put(c, value); } else { map.put(c, 1 ); } } System.out.println(map); } }
小结 略
第四章 集合的嵌套
知识点–集合的嵌套 目标
路径
List嵌套List
List嵌套Map
Map嵌套Map
讲解 List嵌套List 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class Test1 { public static void main (String[] args) { List<String> list1 = new ArrayList<>(); list1.add("王宝强" ); list1.add("贾乃亮" ); list1.add("陈羽凡" ); List<String> list2 = new ArrayList<>(); list2.add("马蓉" ); list2.add("李小璐" ); list2.add("白百何" ); List<List<String>> list = new ArrayList<>(); list.add(list1); list.add(list2); for (List<String> e : list) { for (String name : e) { System.out.println(name); } System.out.println("=============" ); } System.out.println(list); } }
List嵌套Map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class Test2 { public static void main (String[] args) { Map<String,String> map1 = new HashMap<>(); map1.put("it001" ,"迪丽热巴" ); map1.put("it002" ,"古力娜扎" ); Map<String,String> map2 = new HashMap<>(); map2.put("heima001" ,"蔡徐坤" ); map2.put("heima002" ,"李易峰" ); List<Map<String,String>> list = new ArrayList<>(); list.add(map1); list.add(map2); System.out.println(list.size()); for (Map<String, String> map : list) { Set<String> keys = map.keySet(); for (String key : keys) { System.out.println(key + "," + map.get(key)); } } } }
Map嵌套Map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class Test3 { public static void main (String[] args) { Map<String,String> map1 = new HashMap<>(); map1.put("it001" ,"迪丽热巴" ); map1.put("it002" ,"古力娜扎" ); Map<String,String> map2 = new HashMap<>(); map2.put("heima001" ,"蔡徐坤" ); map2.put("heima002" ,"李易峰" ); Map<String, Map<String, String>> map = new HashMap<>(); map.put("传智博客" ,map1); map.put("黑马程序员" ,map2); System.out.println(map.size()); Set<String> keys = map.keySet(); for (String key : keys) { Map<String, String> value = map.get(key); Set<String> keySet = value.keySet(); for (String k : keySet) { String v = value.get(k); System.out.println(k+"," +v); } } } }
小结 第五章 模拟斗地主洗牌发牌 需求 按照斗地主的规则,完成洗牌发牌的动作。
具体规则:
组装54张扑克牌
54张牌顺序打乱
三个玩家参与游戏,三人交替摸牌,每人17张牌 ,最后三张留作底牌。
查看三人各自手中的牌(按照牌的大小排序)、底牌
规则:手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3
分析 1.准备牌:
完成数字与纸牌的映射关系:
使用双列Map(HashMap)集合,完成一个数字与字符串纸牌的对应关系(相当于一个字典)。
2.洗牌:
通过数字完成洗牌发牌
3.发牌:
将每个人以及底牌设计为ArrayList,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
存放的过程中要求数字大小与斗地主规则的大小对应。
将代表不同纸牌的数字分配给不同的玩家与底牌。
4.看牌:
通过Map集合找到对应字符展示。
通过查询纸牌与数字的对应关系,由数字转成纸牌字符串再进行展示。
实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 package com.itheima04;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;public class Test { public static void main (String[] args) { HashMap<Integer, String> pokeBox = new HashMap<>(); ArrayList<String> colors = new ArrayList<>(); ArrayList<String> numbers = new ArrayList<>(); Collections.addAll(colors, "♥" , "♦" , "♠" , "♣" ); Collections.addAll(numbers, "2" , "A" , "K" , "Q" , "J" , "10" , "9" , "8" , "7" , "6" , "5" , "4" , "3" ); int id = 0 ; pokeBox.put(id++, "大王" ); pokeBox.put(id++, "小王" ); for (String number : numbers) { for (String color : colors) { String pai = color + number; pokeBox.put(id++,pai); } } System.out.println(pokeBox.size()); System.out.println(pokeBox); Set<Integer> keySet = pokeBox.keySet(); ArrayList<Integer> idList = new ArrayList<>(); idList.addAll(keySet); Collections.shuffle(idList); System.out.println("打乱顺序后的牌编号:" +idList.size()); System.out.println("打乱顺序后的牌编号:" +idList); ArrayList<Integer> play1Id = new ArrayList<>(); ArrayList<Integer> play2Id = new ArrayList<>(); ArrayList<Integer> play3Id = new ArrayList<>(); ArrayList<Integer> diPaiId = new ArrayList<>(); for (int i = 0 ; i < idList.size(); i++) { Integer paiId = idList.get(i); if (i >= 51 ){ diPaiId.add(paiId); }else if (i%3 ==0 ){ play1Id.add(paiId); }else if (i%3 ==1 ){ play2Id.add(paiId); }else if (i%3 ==2 ){ play3Id.add(paiId); } } Collections.sort(play1Id); Collections.sort(play2Id); Collections.sort(play3Id); Collections.sort(diPaiId); System.out.print("玩家一的牌:" ); for (Integer paiId : play1Id) { String pai = pokeBox.get(paiId); System.out.print(pai+" " ); } System.out.println(); System.out.print("玩家二的牌:" ); for (Integer paiId : play2Id) { String pai = pokeBox.get(paiId); System.out.print(pai+" " ); } System.out.println(); System.out.print("玩家三的牌:" ); for (Integer paiId : play3Id) { String pai = pokeBox.get(paiId); System.out.print(pai+" " ); } System.out.println(); System.out.print("底牌的牌:" ); for (Integer paiId : diPaiId) { String pai = pokeBox.get(paiId); System.out.print(pai+" " ); } } }
小结 略
总结 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 必须练习: 1. Collections工具类的常用方法 2. Map集合的常用方法 3. 自己总结Set集合的继承体系以及各个子集合的特点---->Set接口的介绍 4. HashSet或者HashMap保证元素或者键唯一的原理 5. 自己总结Map集合的继承体系以及各个子集合的特点---->Map接口的介绍 6. 使用Map集合或者Set集合的子类---添加元素,遍历 - 能够使用集合工具类 Collections工具类: - public static void shuffle (List<?> list) :打乱集合顺序。 - public static <T> void sort (List<T> list) :将集合中元素按照默认规则排序。集合元素所属的类必须实现Comparable接口,重写compareTo方法,在该方法中指定排序规则 - public static <T> void sort (List<T> list,Comparator<? super T> ) :将集合中元素按照指定规则排序。 - 能够使用Comparator比较器进行排序 重写compare (T o1,T o2) 方法,指定排序规则 排序规则: 前减后: 升序 后减前: 降序 - 能够使用可变参数 使用格式: 修饰符 返回值类型 方法名(数据类型... 变量名) {} 注意: 1. 一个方法只能有一个可变参数 2. 如果方法有多个参数,可变参数一定要放在最后 - 能够说出Set集合的特点 Set接口:也称Set集合,但凡是实现了Set接口的类都叫做Set集合 特点: 元素无索引,元素不可重复(唯一) HashSet集合: 实现类--元素存取无序 LinkedHashSet集合:实现类--元素存取有序 TreeSet集合:实现类--> 对元素进行排序 注意: 1. Set集合没有特殊的方法,都是使用Collection接口的方法 2. Set集合没有索引,所以遍历元素的方式就只有: 增强for 循环,或者迭代器 - 能够说出哈希表的特点 保证元素唯一 - 使用HashSet集合存储自定义元素 要求该元素所属的类重写hashCode和equals方法 - 能够说出Map集合特点 1. 以键值对的形式存储数据 2. 键唯一,值可重复,如果键重复了,值就会覆盖 3. 根据键找值 - 使用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 boolean containsValue (Object value) :判断该集合中是否有此值 - public Set<K> keySet () : 获取Map集合中所有的键,存储到Set集合中。 - public Collection<V> values () : 获取Map集合中所有的值,存储到Collection集合中。 - public Set<Map.Entry<K,V>> entrySet () : 获取到Map集合中所有的键值对对象的集 - 使用”键找值”的方式遍历Map集合 1.获取所有的键 2.遍历所有的键 3.根据键找值 - 使用”键值对”的方式遍历Map集合 1.获取所有的键值对对象 2.遍历所有的键值对对象 3.根据键值对对象找键或者找值 - 能够使用HashMap存储自定义键值对的数据 键所属的类需要重写hashCode和equals方法 - 能够完成斗地主洗牌发牌案例 略