Bootstrap

JavaSE十二(Set)

Set

3.1 Set集合的概述和特点

Set集合的特点

  • 不包含重复元素的集合
  • 没有带索引的方法,所以不能使用普通for循环遍历

Set集合练习

  • 存储字符串并遍历
/*
	Set集合特点
			不包含重复元素的集合
			没有带索引的方法,所以不能使用普通for循环
	HashSet:对集合的迭代顺序不作任何保证
 */
public class SetDemo {
	public static void main(String[] args) {
		//创建集合对象
		Set<String> set = new HashSet<String>();
		//添加元素
		set.add("hello");
		set.add("world");
		set.add("java");
		//不包含重复元素
		set.add("hello");
		//遍历
		for (String s : set){
			System.out.println(s);
		}
		System.out.println("-------------");
		//迭代器遍历
		Iterator<String> it = set.iterator();
		while (it.hasNext()){
			String next = it.next();
			System.out.println(next);
		}
	}
}

3.2 哈希值

哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

Object类中有一个方法可以获取对象的哈希值

  • public int hashCode():返回对象的哈希码值

对象的哈希值的特点

  • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
  • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
		//创建学生对象
		Student s = new Student("张三",11);

		//同一个对象多次调用hashCode()方法返回的哈希值是相同的
		System.out.println(s.hashCode());//460141958
		System.out.println(s.hashCode());//460141958
		System.out.println("-------");

		Student s2 = new Student("李四",33);
		//默认情况下,不同对象的哈希值是不一样的
		//通过方法重写,可以实现不同对象的哈希值是相同的
		System.out.println(s2.hashCode());//1163157884

3.3 HashSet集合的概述和特点

HashSet集合特点

  • 底层数据结构是哈希表
  • 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的顺序是一致的
  • 没有带索引的方法,不能使用普通for循环遍历
  • 由于是Set集合,所以是不包含重复元素的

HashSet集合练习

  • 储存字符串并遍历
public class HashSetDemo {
	public static void main(String[] args) {
		HashSet<String> hashSet = new HashSet<String>();
		hashSet.add("hello");
		hashSet.add("world");
		hashSet.add("java");
		hashSet.add("java");
		for (String s : hashSet){
			System.out.println(s);
		}
		System.out.println("----------");
		Iterator<String> it = hashSet.iterator();
		while (it.hasNext()){
			String next = it.next();
			System.out.println(next);
		}
	}
}

3.4 HashSet集合保证元素唯一性源码分析

在这里插入图片描述

3.5 常见数据结构之哈希表

在这里插入图片描述

案例:HashSet集合存储学生对象并遍历

需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合

​ 要求:学生成员变量值相同,我们就认为是同一个对象

思路:

  1. 定义学生类

  2. 创建HashSet集合对象

  3. 创建学生对象

  4. 把学生对象添加到集合

  5. 遍历集合对象(增强for)

  6. 在学生类中重写两个方法

    1. ​ hashCode()和euqals()

      ​ 自动生成即可,否则无法保证唯一性。

3.6 LinkedHashSet集合概述和特点

LinkedHashSet集合特点

  • 哈希表和链表实现的Set接口,具有可预测的 迭代次序
  • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
  • 由哈希表保证元素唯一,也就是说没有重复元素

LinkedHashSet集合练习

  • 存储字符并遍历

3.7 TreeSet集合概述和特点

TreeSet集合特点

  • 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体的排序方法取决于构造方法
    • TreeSet():根据其元素的自然排序进行排序
    • TreeSet(Comparator comparator):根据指定的比较器进行排序
  • 没有带索引的方法,所有不能使用普通for循环进行遍历
  • 由于是Set集合,所以不包含重复元素的集合

TreeSet集合练习

  • 存储整数并遍历
public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet<Integer> treeSet =  new TreeSet<Integer>();
		treeSet.add(5);
		treeSet.add(1);
		treeSet.add(3);
		treeSet.add(4);
		treeSet.add(2);

		treeSet.add(2);
		for (Integer i : treeSet){
			System.out.println(i);
		}
	}
}
----------
1
2
3
4
5

3.8 自然排序Comparator的使用

  • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
  • 要求:按照年龄从小到大排序,年龄相同 时,按照姓名的字母排序

结论:

  • 用 TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
  • 自然排序,就是让元素所属的类实现Comparator接口,重写compareTo(To)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

以下是自然排序类实现Comparable接口方法:

public class Student implements Comparable<Student> {
	private String name;
	private int age;

	public Student() {
	}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public int compareTo(Student s) {
		//return 0;//结果只会存储第一个
		//return 1;//按照存储顺序排序
		//return -1;//按照存储顺序倒序排列
		//按照年龄从小到大排序
		int num = this.age - s.age;
		//return num;

		//年龄相同时按照字母顺序排序
		int num2 = num == 0 ? this.name.compareTo(s.name):num;
		return num2;
	}
}
/*
	- 存储学生对象并遍历,创建TreeSet集合使用**无参构造方法**
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母排序
 */
public class TreeSetDemo2 {
	public static void main(String[] args) {
		//创建集合对象
		TreeSet<Student> ts = new TreeSet<Student>();

		//创建学生对象
		Student s1 = new Student("xishi",11);
		Student s2 = new Student("diaocan",14);
		Student s3 = new Student("wangzhaojun",4);
		Student s4 = new Student("yangyuhuan",21);
		Student s5 = new Student("yngyuhuan",21);
		Student s6 = new Student("angyuhuan",21);
		//添加学生对象到集合中
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		//ava.lang.ClassCastException: com.TreeSet.Student cannot be cast to java.lang.Comparable此时必须对象所属的类
		// 实现Comparator接口并重写compareTo(To)方法
		//遍历
		for (Student s : ts){
			System.out.println(s.getName()+","+s.getAge());
		}
	}
}
------------------------
wangzhaojun,4
xishi,11
diaocan,14
angyuhuan,21
yangyuhuan,21
yngyuhuan,21

3.9 比较器Comparator排序的使用

  • 存储学生对象并遍历
  • 要求按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
public class ComparatorDemo {
	public static void main(String[] args) {
		//创建集合对象
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				//this.age - s.age
				//s1, s2
				int num1 = s1.getAge() - s2.getAge();
				int num2 =num1== 0 ? s1.getName().compareTo(s2.getName()) : num1;
				return num2;
			}
		});
		//创建学生对象
		Student s1 = new Student("zhangsan",32);
		Student s2 = new Student("lisi",42);
		Student s6 = new Student("lisi",42);
		Student s7 = new Student("lisi",3);

		Student s3 = new Student("wangwu",15);
		Student s4 = new Student("chenliu",22);
		Student s5 = new Student("ahenliu",22);

		//向集合中添加元素
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		ts.add(s7);

		//遍历集合
		for (Student s : ts){
			System.out.println(s.getName()+","+s.getAge());
		}
	}
}
-------------------------
运行结果:
		lisi,3
        wangwu,15
        ahenliu,22
        chenliu,22
        zhangsan,32
        lisi,42

结论

  • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序 对元素进行排序的
  • 用比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写Compare(T o1,T o2)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

案例:成绩排序

需求:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合
要求:按照总分从高到底出现

思路:

  1. 定义学生类
  2. 创建TreeSet集合对象,通过比较器排序进行排序
  3. 创建学生对象
  4. 把学生对象添加到集合
  5. 遍历集合

比较器排序

public class TreeSetDemo {
	public static void main(String[] args) {
		//创建TreeSet集合对象
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				//int num = (s2.getMathGrade() + s2.getChinese()) - (s1.getChinese() + s1.getMathGrade());
				//主要条件
				int num = s2.getSum() - s1.getSum();
				//次要条件
				int num2 = num == 0 ? s1.getChinese() - s2.getChinese()  : num;
				int num3 = num2==0?s1.getName().compareTo(s2.getName()):num2;
				return num3;
			}
		});

		//创建学生对象
		Student s1 = new Student("aaa", 100, 80);
		Student s2 = new Student("wgwe", 63, 74);
		Student s3 = new Student("age", 64, 93);
		Student s4 = new Student("betw", 95, 99);
		Student s5 = new Student("ggag", 90, 90);
		Student s6 = new Student("ggag", 95, 99);
		//添加学生对象到集合
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		//增强for遍历
		for (Student s : ts) {
			System.out.println(s.getName() + "," + s.getMathGrade() + "," + s.getChinese() + "," + s.getSum());
		}
	}
}
-----------
运行结果:
    betw,99,95,194
    ggag,99,95,194
    ggag,90,90,180
    aaa,80,100,180
    age,93,64,157
    wgwe,74,63,137

自然排序:

public class Student1 implements Comparable<Student1> {
	private String name;
	private int chinese;
	private int Math;

	public Student1() {
	}

	public Student1(String name, int chinese, int math) {
		this.name = name;
		this.chinese = chinese;
		Math = math;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getChinese() {
		return chinese;
	}

	public void setChinese(int chinese) {
		this.chinese = chinese;
	}

	public int getMath() {
		return Math;
	}

	public void setMath(int math) {
		Math = math;
	}
	public int getSum(){
		return chinese+Math;
	}

	@Override
	public int compareTo(Student1 s) {
        //主要条件
		int num = s.getSum() - this.getSum();
        //次要条件
		int num2 = num == 0?s.Math-this.Math:num;
		int num3 = num2==0?s.name.compareTo(this.name):num2;
		return num3;
	}
}
---------------------
package com.Test1;

import java.util.TreeSet;

public class TreeSetDemo2 {
	public static void main(String[] args) {
		//创建TreeSet集合对象
		TreeSet<Student1> ts = new TreeSet<Student1>();

		//创建学生对象
		Student1 s1 = new Student1("张三", 99, 100);
		Student1 s2 = new Student1("李四", 79, 100);
		Student1 s3 = new Student1("王五", 99, 93);
		Student1 s4 = new Student1("赵六", 99, 84);
		Student1 s5 = new Student1("陈柒", 84, 99);
		Student1 s6 = new Student1("二柒", 79, 100);
		//添加
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		//遍历
		for (Student1 s : ts) {
			System.out.println(s.getName() + "," + s.getChinese() + "," + s.getMath());
		}
	}
}
----------------
张三,99,100
王五,99,93
陈柒,84,99
赵六,99,84
李四,79,100
二柒,79,100

案例:不重复的随机数

需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出

思路:

  1. 创建Set集合对象
  2. 创建随机数对象
  3. 判断集合的长度是不是小于10
    1. 是:产生一个随机数,添加到集合
    2. 否:回到3继续
  4. 遍历集合
/*
	需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出
 */
public class SetDemo {
	public static void main(String[] args) {
		//创建Set集合对象
		//Set<Integer> set = new HashSet<Integer>();
		Set<Integer> set = new TreeSet<Integer>();

		//创建随机数对象
		Random r = new Random();

		//判断集合是否小于10
		while (set.size() < 10) {
			//添加一随机数
			int i = r.nextInt(20)+1;
			//添加随机数到集合
			set.add(i);
		}
		//遍历集合
		for (Integer s : set) {
			System.out.println(s);
		}
	}
}

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;