大数据之路week02 Collection 集合体系收尾(Set)

1、Set集合(理解)

  (1)Set集合的特点

    无序,唯一。

  (2)HashSet集合(掌握)

    A: 底层数据结构是哈希表(是一个元素为链表的数组)

    B: 哈希表底层依赖两个方法: hashCode() 和 equals()

      执行顺序:

        首先比较哈希值是否相同

          相同:继续执行equals()方法

            返回true:元素重复了,不添加

            返回false:直接把元素添加到集合

          不同:就直接把元素添加到集合

1、人的类

 1 package com.wyh.hashSet;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月17日 上午9:21:02
 6 */
 7 public class Person {
 8     private String name;
 9     private int age;
10     
11     public Person(String name, int age) {
12         super();
13         this.name = name;
14         this.age = age;
15     }
16     public Person() {
17         super();
18         // TODO Auto-generated constructor stub
19     }
20     
21     public String getName() {
22         return name;
23     }
24     public void setName(String name) {
25         this.name = name;
26     }
27     public int getAge() {
28         return age;
29     }
30     public void setAge(int age) {
31         this.age = age;
32     }
33     
34     //重写hashCode方法和equals方法
35     @Override
36     public int hashCode() {
37         final int prime = 31;
38         int result = 1;
39         result = prime * result + age;
40         result = prime * result + ((name == null) ? 0 : name.hashCode());
41         return result;
42     }
43     @Override
44     public boolean equals(Object obj) {
45         if (this == obj)
46             return true;
47         if (obj == null)
48             return false;
49         if (getClass() != obj.getClass())
50             return false;
51         Person other = (Person) obj;
52         if (age != other.age)
53             return false;
54         if (name == null) {
55             if (other.name != null)
56                 return false;
57         } else if (!name.equals(other.name))
58             return false;
59         return true;
60     }
61     
62 
63 }

2、测试类:

 1 package com.wyh.hashSet;
 2 
 3 import java.util.HashSet;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月17日 上午9:21:16
 8 */
 9 public class HashSetDemo01 {
10     public static void main(String[] args) {
11         //创建HashSet集合
12         HashSet<Person> hs = new HashSet<Person>();
13         
14         //创建Person类
15         Person p1 = new Person("小虎",22);
16         Person p2 = new Person("小强",23);
17         Person p3 = new Person("小虎",22);
18         Person p4 = new Person("小美",21);
19         Person p5 = new Person("小雪",21);
20         
21         //将对象添加到HashSet中去
22         hs.add(p1);
23         hs.add(p2);
24         hs.add(p3);
25         hs.add(p4);
26         hs.add(p5);
27         
28         
29         //遍历
30         for(Person p : hs) {
31             System.out.println(p.getName()+"---"+p.getAge());
32             
33             
34         }
35     }
36 
37 }

3、如下图,如果不重写hashCode()方法和equals()方法,运行结果,可以运行不报错,但是重复的元素也加入了。

4、重写后:

    C:如何保证元素的唯一性呢?

      由hashCode()和equals()保证的(如下图,流程)

 

 

 

    D:开发的时候,代码非常的简单,自动生成即可。

    E:HashSet存储字符串并遍历

 1 package com.wyh.set;
 2 
 3 import java.util.HashSet;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月16日 下午7:42:24
 8 * 
 9 * HashSet在存储字符串的时候,为什么只存储相同的字符串只存储一个呢?
10 * 通过查看add方法的源码,我们发现这个方法的底层方法是依赖两个方法,hashCode()和equals() 
11 * 
12 * 
13 */
14 public class HashSetDemo01 {
15     public static void main(String[] args) {
16         HashSet<String> hs = new HashSet<String>();
17         
18         hs.add("Hello");
19         hs.add("World");
20         hs.add("Java");
21         hs.add("World");
22         
23         for(String s : hs) {
24             System.out.println(s);
25         }
26     
27     }
28 
29 }

    F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)

  (3)TreeSet集合

    A:底层数据结构是红黑树(是一个自平衡的二叉树)

 

 

 

    B:  保证元素的排序方式

      a: 自然排序(元素具备比较性)

        让元素所属的类实现Comparable接口(难点,需求会给出主要条件,但是需要我们分析次要条件,例如 需求是根据年龄的长度进行排序,但是我们还要考虑姓名的长度和内容)

学生类:

 1 package com.wyh.treeSet;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月17日 上午11:13:45
 6 */
 7 public class Student2 implements Comparable<Student2>{
 8     private String name;
 9     private int age;
10     public Student2(String name, int age) {
11         super();
12         this.name = name;
13         this.age = age;
14     }
15     public Student2() {
16         super();
17         // TODO Auto-generated constructor stub
18     }
19     public String getName() {
20         return name;
21     }
22     public void setName(String name) {
23         this.name = name;
24     }
25     public int getAge() {
26         return age;
27     }
28     public void setAge(int age) {
29         this.age = age;
30     }
31     @Override
32     public int compareTo(Student2 s) {
33         int num = this.name.length() - s.name.length();
34         //次要条件1 姓名长度一样,内容不一定一样
35         int num2 = num == 0 ? (this.name.compareTo(s.name)) : num;
36         //次要条件2 姓名长度和内容一样,年龄不一定一样
37         int num3 = num2 == 0 ? this.age - s.age : num2;
38         return num3;
39         
40     }
41     
42     
43     
44     
45 }

测试类:

如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
// java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
// java.lang.Comparable

 1 package com.wyh.treeSet;
 2 
 3 import java.util.TreeSet;
 4 
 5 /**
 6  * @author WYH
 7  * @version 2019年11月17日 下午2:27:13
 8  * 
 9  *          根据年龄的长度进行排序
10  */
11 public class TreeSetDemo03 {
12     public static void main(String[] args) {
13         TreeSet<Student2> ts = new TreeSet<Student2>();
14 
15         // 创建学生对象
16         Student2 s1 = new Student2("王友虎", 22);
17         Student2 s2 = new Student2("赵以浩", 24);
18         Student2 s3 = new Student2("齐博源", 21);
19         Student2 s4 = new Student2("李先锋", 23);
20         Student2 s5 = new Student2("李宏灿", 22);
21         Student2 s6 = new Student2("薛长城", 23);
22         Student2 s7 = new Student2("黄天祥", 24);
23         Student2 s8 = new Student2("王友虎", 23);
24 
25         // 添加到TreeSet中
26         ts.add(s1);
27         ts.add(s2);
28         ts.add(s3);
29         ts.add(s4);
30         ts.add(s5);
31         ts.add(s6);
32         ts.add(s7);
33         ts.add(s8);
34 
35         // 遍历
36         // 如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
37         // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
38         // java.lang.Comparable
39         for (Student2 s : ts) {
40             System.out.println(s.getName() + "---" + s.getAge());
41         }
42 
43     }
44 
45 

      b: 比较器排序(集合具备比较性)

        让集合构造方法接收Comparator的实现类对象(但是我们一般用匿名内部类的方式实现)

方式1、我们不用内部类的方式实现:

定义一个类实现Comparator<T> 接口,重写compare方法:

 1 package com.wyh.treeSet2;
 2 
 3 import java.util.Comparator;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月17日 下午2:48:22
 8 */
 9 public class MyComparator implements Comparator<Student2> {
10 
11     @Override
12     public int compare(Student2 s1, Student2 s2) {
13         int num = s1.getName().length() - s2.getName().length();
14         int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
15         int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
16         return num3;
17     }
18 
19     
20 
21 }

测试类:

 1 package com.wyh.treeSet2;
 2 
 3 import java.util.Comparator;
 4 import java.util.TreeSet;
 5 
 6 /**
 7  * @author WYH
 8  * @version 2019年11月17日 下午2:27:13
 9  * 
10  *          根据年龄的长度进行排序
11  */
12 public class TreeSetDemo03 {
13     public static void main(String[] args) {
14 //        TreeSet<Student2> ts = new TreeSet<Student2>();
15         TreeSet<Student2> ts = new TreeSet<Student2>(new MyComparator());
16         
17         //如果一个方法的参数是接口,那么真正要的是实现这个接口的实现类
18         //匿名内部类可以是实现
19        /* TreeSet<Student2> ts = new TreeSet<Student2>(new Comparator<Student2>(){
20             @Override
21             public int compare(Student2 s1, Student2 s2) {
22                 int num = s1.getName().length() - s2.getName().length();
23                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
24                 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
25                 return num3;
26             }
27         });*/
28  
29         // 创建学生对象
30         Student2 s1 = new Student2("王友虎", 22);
31         Student2 s2 = new Student2("赵以浩", 24);
32         Student2 s3 = new Student2("齐博源", 21);
33         Student2 s4 = new Student2("李先锋", 23);
34         Student2 s5 = new Student2("李宏灿", 22);
35         Student2 s6 = new Student2("薛长城", 23);
36         Student2 s7 = new Student2("黄天祥", 24);
37         Student2 s8 = new Student2("王友虎", 23);
38 
39         // 添加到TreeSet中
40         ts.add(s1);
41         ts.add(s2);
42         ts.add(s3);
43         ts.add(s4);
44         ts.add(s5);
45         ts.add(s6);
46         ts.add(s7);
47         ts.add(s8);
48 
49         // 遍历
50         // 如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
51         // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
52         // java.lang.Comparable
53         for (Student2 s : ts) {
54             System.out.println(s.getName() + "---" + s.getAge());
55         }
56 
57     }
58 
59 }

方式2、用匿名内部类的方式实现:

 1 package com.wyh.treeSet2;
 2 
 3 import java.util.Comparator;
 4 import java.util.TreeSet;
 5 
 6 /**
 7  * @author WYH
 8  * @version 2019年11月17日 下午2:27:13
 9  * 
10  *          根据年龄的长度进行排序
11  */
12 public class TreeSetDemo03 {
13     public static void main(String[] args) {
14 //        TreeSet<Student2> ts = new TreeSet<Student2>();
15 //        TreeSet<Student2> ts = new TreeSet<Student2>(new MyComparator());
16         
17         //如果一个方法的参数是接口,那么真正要的是实现这个接口的实现类
18         //匿名内部类可以是实现
19         TreeSet<Student2> ts = new TreeSet<Student2>(new Comparator<Student2>(){
20             @Override
21             public int compare(Student2 s1, Student2 s2) {
22                 int num = s1.getName().length() - s2.getName().length();
23                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
24                 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
25                 return num3;
26             }
27         });
28  
29         // 创建学生对象
30         Student2 s1 = new Student2("王友虎", 22);
31         Student2 s2 = new Student2("赵以浩", 24);
32         Student2 s3 = new Student2("齐博源", 21);
33         Student2 s4 = new Student2("李先锋", 23);
34         Student2 s5 = new Student2("李宏灿", 22);
35         Student2 s6 = new Student2("薛长城", 23);
36         Student2 s7 = new Student2("黄天祥", 24);
37         Student2 s8 = new Student2("王友虎", 23);
38 
39         // 添加到TreeSet中
40         ts.add(s1);
41         ts.add(s2);
42         ts.add(s3);
43         ts.add(s4);
44         ts.add(s5);
45         ts.add(s6);
46         ts.add(s7);
47         ts.add(s8);
48 
49         // 遍历
50         // 如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
51         // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
52         // java.lang.Comparable
53         for (Student2 s : ts) {
54             System.out.println(s.getName() + "---" + s.getAge());
55         }
56 
57     }
58 
59 }

  (4)案例:

    A: 获取无重复的随机数(HashSet实现)

 1 package com.wyh.HashSet_random;
 2 
 3 import java.util.Arrays;
 4 import java.util.HashSet;
 5 import java.util.Random;
 6 
 7 /** 
 8 * @author WYH
 9 * @version 2019年11月17日 下午3:14:10
10 * 
11 * 实现10个1-20的随机数
12 * 
13 * 
14 * 
15 */
16 public class HashSet_random_Demo {
17     public static void main(String[] args) {
18         //创建随机数对象
19         Random r = new Random();
20         
21         //创建HashSet集合
22         HashSet<Integer> hs = new HashSet<Integer>();
23         
24         //判断元素是否小于10
25         while(hs.size()<10) {
26            int num = r.nextInt(20)+1;
27            hs.add(num);
28         }
29         
30         Object[] obj = hs.toArray();
31         Arrays.sort(obj);
32         
33         //遍历集合
34         for(Object i : obj) {
35             System.out.println(i);
36         }
37     }
38 }

    B: 键盘录入学生按照总分从搞到底输出(TreeSet且用匿名内部类实现)

 1 package TreeSet_Scanner;
 2 
 3 import java.util.Comparator;
 4 import java.util.Scanner;
 5 import java.util.TreeSet;
 6 
 7 
 8 /** 
 9 * @author WYH
10 * @version 2019年11月17日 下午3:25:25
11 * 
12 * 键盘录入5个学生信息,并且按照总分高低排序
13 */
14 public class TreeSetDemo {
15     public static void main(String[] args) {
16         //创建控制台输入对象
17         Scanner sc = new Scanner(System.in);
18         
19         TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){
20             @Override
21             public int compare(Student s1, Student s2) {
22                 /*int num = s1.getName().length() - s2.getName().length();
23                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
24                 int num3 = num2 == 0 ? s1.getSum() - s2.getSum() : num2;
25                 return num3;*/
26                 int num = s2.getSum() - s1.getSum();
27                 int num2 = num == 0 ? s1.getMathNum() - s2.getMathNum() : num;
28                 int num3 = num2 == 0 ? s1.getChinaNum() - s2.getChinaNum() : num2;
29                 int num4 = num3 == 0 ? s1.getEngnishNum() - s2.getEngnishNum() : num3;
30                 int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()) : num4;
31                 return num5;
32             }
33         });
34         
35         
36         System.err.println("录入开始:");
37         for(int i = 0 ; i < 5 ; i++) {
38             Student s = new Student();
39             System.out.print("请输入第"+(i+1)+"个学生的姓名:");
40             String name = sc.next();
41             s.setName(name);
42             System.out.print("请输入该学生的数学成绩:");
43             int mNum = sc.nextInt();
44             s.setMathNum(mNum);
45             System.out.print("请输入该学生的语文成绩:");
46             int cNum = sc.nextInt();
47             s.setChinaNum(cNum);
48             System.out.print("请输入该学生的英语成绩:");
49             int eNum = sc.nextInt();
50             s.setEngnishNum(eNum);
51             
52             int sum = mNum + cNum + eNum;
53             s.setSum(sum);
54             
55             ts.add(s);
56             System.out.println();
57         }
58         System.err.println("录入结束!");
59         
60         System.out.println("姓名\t数学成绩\t语文成绩\t英语成绩\t总分");
61         for(Student s : ts) {
62             System.out.println(s.getName()+"\t"+s.getMathNum()+"\t"+s.getChinaNum()+"\t"+s.getEngnishNum()
63             +"\t"+s.getSum());
64         }
65         
66         
67     }
68 
69 }

2、Collection 集合体系 总结:

我们学完了Set集合,这个Collection体系下的另一个大模块,我们再来总结一下,把漏的LinkedList也总结一下:

  Collection

    | - - List 有序,可重复

      | - - ArrayList

          底层数据结构是数组,查询快,增删慢。

          线程不安全,效率高。

      | - - Vector

          底层数据结构是数组,查询快,增删慢。

          线程安全,效率低。

      | - - LinkedList

          底层数据结构是链表,查询慢,增删快。

          线程不安全,效率高。

    | - - Set 无序,唯一

      | - - HashSet

          底层数据结构是哈希表。

          如何保证元素唯一性的呢?

            依赖两个方法:hashCode()和equals()方法

            开发中自动生成这两个方法即可。

          | - - LinkedHashSet

            底层数据结构是链表和哈希表

            由链表保证元素有序

            由哈希表保证元素唯一

人的类:重写方法

 1 package com.wyh.linkedHashSet;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月17日 上午9:21:02
 6 */
 7 public class Person {
 8     private String name;
 9     private int age;
10     
11     public Person(String name, int age) {
12         super();
13         this.name = name;
14         this.age = age;
15     }
16     public Person() {
17         super();
18         // TODO Auto-generated constructor stub
19     }
20     
21     public String getName() {
22         return name;
23     }
24     public void setName(String name) {
25         this.name = name;
26     }
27     public int getAge() {
28         return age;
29     }
30     public void setAge(int age) {
31         this.age = age;
32     }
33     
34     //重写hashCode方法和equals方法
35     @Override
36     public int hashCode() {
37         final int prime = 31;
38         int result = 1;
39         result = prime * result + age;
40         result = prime * result + ((name == null) ? 0 : name.hashCode());
41         return result;
42     }
43     @Override
44     public boolean equals(Object obj) {
45         if (this == obj)
46             return true;
47         if (obj == null)
48             return false;
49         if (getClass() != obj.getClass())
50             return false;
51         Person other = (Person) obj;
52         if (age != other.age)
53             return false;
54         if (name == null) {
55             if (other.name != null)
56                 return false;
57         } else if (!name.equals(other.name))
58             return false;
59         return true;
60     }
61     
62 
63 }

测试类:

 1 package com.wyh.linkedHashSet;
 2 
 3 import java.util.LinkedHashSet;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月17日 上午9:40:25
 8 * 
 9 * LinkedHashSet: 底层是由哈希表和链表实现的
10 * 
11 * 哈希表确保元素的唯一性
12 * 链表确保元素有序(存储和取出一致 )
13 */
14 public class LinkedHashSetDemo1 {
15     public static void main(String[] args) {
16         LinkedHashSet<Person> lhs = new LinkedHashSet<Person>();
17         //创建Person类
18         Person p1 = new Person("小虎",22);
19         Person p2 = new Person("小强",23);
20         Person p3 = new Person("小虎",22);
21         Person p4 = new Person("小美",21);
22         Person p5 = new Person("小雪",21);
23         
24         lhs.add(p1);
25         lhs.add(p2);
26         lhs.add(p3);
27         lhs.add(p4);
28         lhs.add(p5);
29         
30         //
31         for(Person p : lhs) {
32             System.out.println(p.getName()+"---"+p.getAge());
33         }
34         
35     }
36 
37 }

      | - - TreeSet

          底层数据结构是红黑树。

          如何保证元素的排序的呢?

            自然排序

            比较器排序

          如何保证元素唯一性呢?

            根据比较的返回值是否是0来决定

3、针对Collection集合我们到底使用谁呢?

    唯一吗?

      是:Set

        排序吗?

          是:TreeSet

          否:HashSet

      如果知道是Set,但是不知道是哪个Set,就用HashSet。

      否:List

        要安全吗?

          是:vector

          否:ArrayList 或者 LinkedList

            查询多:ArrayList

            增删多:LinkedList

      如果知道是List,但是不知道是哪个List,就用ArrayList。

    如果知道使用Collection集合,但是不知道使用谁,就用ArrayList。

  如果知道是用集合,就用ArrayList.

4、在集合中常见的数据结构

  ArrayXxx:底层数据结构是数组,查询快,增删慢。 

  LinkedXxx: 底层数据结构是链表,查询慢,增删快。

  HashXxx: 底层数据结构是哈希表,依赖两个方法:hashCode() 和equals()方法

  TreeXxx: 底层数据结构是二叉树,两种方式排序,自然排序和比较器排序。

 

posted @ 2019-11-17 22:49  Xiaohu_BigData  阅读(168)  评论(0编辑  收藏  举报