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: 底层数据结构是二叉树,两种方式排序,自然排序和比较器排序。