Set集合

一. ArrayList嵌套

  1. 定义

    • 在集合中存放集合,和二维数组类似
  2. 演示

    public static void main(String[] args) {
    	//集合中的元素还是集合
    	ArrayList<ArrayList<Student>> school = new ArrayList<>();
    	
    	ArrayList<Student> clas1 = new ArrayList<>();
    	clas1.add(new Student("小红",18));
    	clas1.add(new Student("小明", 20));
    	
    	school.add(clas1);
    	
    	ArrayList<Student> clas2 = new ArrayList<>();
    	clas2.add(new Student("小张",18));
    	clas2.add(new Student("小李", 20));
    	school.add(clas2);
    	
    	ArrayList<Student> clas3 = new ArrayList<>();
    	clas3.add(new Student("tom",18));
    	clas3.add(new Student("jack", 20));
    	school.add(clas3);
    	
    	System.out.println(school);
    }
    
  3. 测试题

    • 需求: 先有一家宾馆,宾馆中有多个房间, 每个房间有数量不等客人, 使用集合嵌套的形式模拟并打印所有人的信息

二. Set集合

  1. 定义

    • Set集合存数的元素是无序的, 而且不允许储存重复的元素, 每当有新的元素存入的时候,Set集合会先去过滤, 如果发现和集合中现有元素出现重复, 就不在允许添加
  2. 应用场景

    • 当我们不想让集合中出现重复的元素时,使用Set集合
    • 当我们需要排除重复数据时,使用Set集合
  3. 演示

    public static void main(String[] args) {
    	//集合中的元素还是集合
    	HashSet<Student> s = new HashSet<>();
    	
    	Student student = new Student("小红", 18);
    	Student student2 = new Student("小红", 18);
    
    	s.add(student);
    	s.add(student2);
    	
    	Iterator<Student> it = s.iterator();
    	while (it.hasNext()) {
    		Student student3 = it.next();
    		System.out.println(student3);
    	}
    }
    

三. HashSet

  1. 定义

    • HashSet集合中的元素是通过hash值来比较是否相同
    • 集合通过元素的hashCode和equals方法来比较两个元素是否相同, 不同就存入, 相同不存入
    • 元素存入的位置未知,和存入的顺序无关
  2. 存储原理

    • HashSet最后还是存入数组中, 只是根据元素的Hash值来确定存入的角标位置
      • 元素的hash值 ^ (元素的hash值 >>> 16) & (数组的长度-1)
    • HashSet中不是直接存入我们给定的元素, 而是用集合中的一个内部类封装我们存入的元素,所以当我们存入null的时候,不会因为和数组中角标位上默认值null起冲突
    • 如果两个不同的元素根据不同的Hash值计算出了同一个角标值,那么都能存进去
  3. 构造方法

    • HashSet() 构造出一个新的集合, 底层数组默认的初始容量是16(扩容一倍),加载因子是0.75
      • 加载因子: 集合中的数组可用的
      • 角标值得可选范围越小,计算出重复角标值得概率就越高
    • HashSet(Collection<? extends E> c) 构造一个包含指定collection中元素的新set
  4. 常用方法

    • boolean add( E e) 如果此set集合中尚未包含指定元素,则添加指定元素
    • boolean remove(Object o) 移除某个元素 []
    • int size() 获取集合的长度
  5. 演示

    • 需求: 去除ArrayList集合中的重复元素
    public static void main(String[] args) {
    
    	ArrayList<String> al = new ArrayList<>();
    	al.add("a");
    	al.add("s");
    	al.add("x");
    	al.add("a");
    	al.add("s");
    	
    	HashSet<String> hs = new HashSet<>(al);
    	System.out.println(hs);
    }
    
  6. 测试题

    • 需求: 创建Student类, 定义name和age属性, 创建多个对象(有属性重复的对象)存入ArrayList集合中, 然后对集合中的元素去重

四. HashSet集合中元素保证唯一性

  1. 原理解析

    • HashSet是通过调用元素的hashCode和equals方法来比较两个元素是否形同的,所以如果要保证引用数据类型逻辑上的唯一性,就必须重写hashCode方法和equals方法
    • 演示
    public int hashCode() {
    	final int prime = 31;
    	int result = 1;
    	result = prime * result + age;
    	result = prime * result + ((name == null) ? 0 : name.hashCode());
    	return result;
    }
    
    • prime = 31 的原因
      • 别人选的, 没有原因
      • 是质数, 和别的值计算得出的数重复的概率低
      • 大小适中, 不会出现太大导致结果无法使用的问题
      • 便于计算 2<<5 -1
  2. 引用数据类型除重

    • 重写hashCode和equals方法,自定义比较内容
  3. 测试题

    • 需求: 编写程序, 获取10个1到20的随机数, 要求随机数不能重复, 打印结果
    public static void main(String[] args) {
    
    	Random random = new Random();
    	
    	HashSet<Integer> hashSet = new HashSet<>();
    	
    	while(hashSet.size()<10){
    		int num = random.nextInt(20)+1;
    		hashSet.add(num);
    	}
    	System.out.println(hashSet);
    }
    
  4. 测试题

    • 需求: 从键盘录入一行数据, 去掉其中重复的字符,打印结果
    public static void main(String[] args) {
    	Scanner sc = new Scanner(System.in);
    
    	System.out.println("请输入一行字符串:");
    	String line = sc.nextLine();					//将键盘录入的字符串存储在line中
    	char[] arr = line.toCharArray();				//将字符串转换成字符数组
    	HashSet<Character> hs = new HashSet<>();		//创建HashSet集合对象
    
    	for (int i = 0; i < arr.length; i++) {
    		hs.add(arr[i]);
    	}
    
    	Iterator<Character> it = hs.iterator();
    	while (it.hasNext()) {
    		System.out.print(it.next());
    	}
    	
    	sc.close();
    }
    
  5. 测试题

    • 产生10个随机的字符串, 要求不能重复(字符串中的字符取值在 ‘a’ 到 ‘z’ , ‘A’ 到 ‘Z’ ,‘0’ 到 ‘9’),字符串的长度1-20

五. LinkedHashSet

  1. 定义

    • 兼顾了linked的有序性和HashSet的元素唯一性
  2. 演示

    public static void main(String[] args) {
    
    	HashSet<String> hashSet = new HashSet<>();
    	
    	hashSet.add("b");
    	hashSet.add("c");
    	hashSet.add("a");
    	hashSet.add("d");
    	
    	System.out.println(hashSet); //结果 : [a, b, c, d]
    	
    	LinkedHashSet<String> lhs = new LinkedHashSet<>();
    	lhs.add("b");
    	lhs.add("c");
    	lhs.add("a");
    	lhs.add("d");
    	System.out.println(lhs); //结果: [b, c, a, d]
    }
    

六. TreeSet集合

  1. 定义

    • TreeSet是一种顺序的集合, 记住, 这里的顺序是指集合中的元素有顺序, 她是通过比较元素的大小来存放的, 大的存右边,小的存左边
    • 存入的元素必须实现Comparable接口,并且重写comparTo方法
    • 最后存入的元素会形成一个树状结构
  2. 构造方法

    • TreeSet() 构造一个新的空set, 该set根据其元素的自然顺序进行排序
    • TreeSet(Comparator <? super E> comparator) 构建一个空的TreeSet, 他根据指定比较器进行排序
  3. 常用方法

    • add(E e) 将指定元素添加到此set
    • first() 返回此set中当前第一元素
    • last() 返回此set中当前最后一个元素
    • floor() 返回此set中小于等于给定元素的最大元素,不存在则返回null
    • higher() 返回此set中严格大于给定元素的最小元素,不存在则返回null
  4. 演示

    public static void main(String[] args) {
    	TreeSet<String> set = new TreeSet<>();
    	
    	set.add("a");
    	set.add("d");
    	set.add("c");
    	set.add("b");
    	set.add("e");
    	set.add("b");
    	set.add("n");
    	
    	System.out.println(set);//结果: [a, b, c, d, e, n]
    }
    
  5. 添加原理

    • TreeSet会将第一个添加的元素作为中点, 以后添加的元素会先跟中点进行比较, 如果大于就接着跟所比较元素的右边的元素接着比较,如果小于就接着跟所比较元素左边的元素接着比较, 直到无法找到可比较的元素,就会将新添加的这个元素放到当前位置
  6. Comparable接口

    • 所有存入的元素在比较的时候,如果集合没有比较器, 就会将元素本身转成Comparator类型并调用comparTo方法进行比较, 所以我们必须实现Comparato接口,并重写comparTo方法
    • 调用compartTo方法比较
      • 如果方法返回一个小于0的数,表示当前元素小于被比较元素
      • 如果返回 0 表示当前元素等于被比较元素
      • 如果返回一个大于0的数, 表示当前元素大于被比较元素
    • 演示
    public class Student implements Comparable<Student>{
    
    	@Override
    	public int compareTo(Student o) {
    		
    		return 0;
    	}
    
    }
    
  7. Comparator比较器

    • 这是一个接口, 定义了一个compare抽象方法
    • compare方法可以对两个元素进行比较
      • 如果方法返回一个小于0的数,表示参数1小于参数2
      • 如果返回 0 ,表示参数1等于参数2
      • 如果返回一个大于0的数, 表示参数1大于参数2
    • 演示
    public class MyComparator implements  Comparator<Student>{
    
    	@Override
    	public int compare(Student o1, Student o2) {
    		
    		return 1;
    	}
    }
    
  8. 注意事项

    • TreeSet集合的存储原理限定了必须要对存入的元素进行比较
    • 要么存入的元素自身实现Comparable接口, 要么提供外部的实现了Comparator接口的比较器, 否则程序运行就会报错
  9. 测试题

    • 需求: 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
    • 演示
    public class MyComparator implements Comparator<Student>{
    
    	@Override
    	public int compare(Student o1, Student o2) {
    		int num = o2.getSum() - o1.getSum();			//根据学生的总成绩降序排列
    		return num ;
    	}
    }
    
    public static void main(String[] args) {
    	
    	TreeSet<Student> set = new TreeSet<>(new MyComparator());
    	
    	Student student1 = new Student("小红",100);
    	Student student2 = new Student("小明",50);
    	Student student3 = new Student("小李",60);
    	set.add(student1);
    	set.add(student2);
    	set.add(student3);
    	
    	for (Student student : set) {
    		System.out.println(student);
    	}
    }
    

七. 超级for

  1. 定义

    • Iterator的简写形式
    • 简化数组和Collection集合的遍历
  2. 格式

    for(元素数据类型 变量 : 数组或者Collection集合) {
    	使用变量即可,该变量就是当前元素
    }
    
  3. 演示

    public static void main(String[] args) {
    	
    	TreeSet<Student> set = new TreeSet<>(new MyComparator());
    	
    	Student student1 = new Student("小红");
    	Student student2 = new Student("小明");
    	Student student3 = new Student("小李");
    	set.add(student1);
    	set.add(student2);
    	set.add(student3);
    	
    	for (Student student : set) {
    		System.out.println(student);
    	}
    }
    
  4. 三种迭代方式的删除

    • 普通for循环,可以删除,但是需要角标
    • 迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
    • 超级for循环不能删除

八. Collections工具类的使用

  1. 定义

    • 一个用于操作Collection集合工具类
  2. 常用方法

    • sort(List list) 根据元素的自然顺序排序
    • swap(List list , int i , int j) 交换集合中两个角标位上的值
    • reverse(List<?> list ) 反转集合中的元素的顺序
    • replaceAll(List list, T oldVal, T newVal) 替换
  3. 演示

    public static void main(String[] args) {
    	
    	List<String> cl = new ArrayList<>();
    	
    	cl.add("a");
    	cl.add("d");
    	cl.add("s");
    	cl.add("t");
    	cl.add("a");
    	cl.add("e");
    	
    	System.out.println(cl);//[a, d, s, t, a, e]
    	
    	Collections.sort(cl);
    	System.out.println(cl);//[a, a, d, e, s, t]
    	
    	Collections.swap(cl,1,2);
    	System.out.println(cl);//[a, d, a, e, s, t]
    	
    	Collections.reverse(cl);
    	System.out.println(cl);//[t, s, e, a, d, a]
    	
    	Collections.replaceAll(cl,"a","f");
    	System.out.println(cl);//[t, s, e, f, d, f]
    }
    

总结

  1. ArrayList集合的嵌套

    类似于二维数组, 集合中存储集合

  2. Set

    无序 : 集合无序/容器无序

    去重(有用) : 如果代码中没有去重,不要使用set集合, 如果有去重, 一定要set集合,效率贼高

  3. HashSet

    底层是数组, 元素需要根据hash值计算出一个角标,在存到数组中 , 所以, 集合中元素的数量不影响去重的效率

    自定一定类型, 必须要重写hashCode和equals方法才能去

  4. LinkedHashSet

    容器有序的还能去重的集合

    两边的效率都不高

  5. TreeSet

    去重, 元素还是有序的

    红黑树

    集合必须有比较的功能: 1. 元素本身具备比较的能力, 2. 使用第三方比较器

  6. 超级for

    迭代器的简写形式 , 省略很多重复的步骤

    不能删除

  7. Collections

    操作集合的工具类

作业

  1. 第一题
    • 需求: 创建学生类, 定义姓名和年龄属性, 创建多个学生对象, 根据学生的年龄进行排序
  2. 第二题
    • 需求: 从键盘接收一个字符串, 程序对其中所有字符进行排序(重复不重复无所谓啦)
    • 示例: 键盘输入: helloitcast程序打印:acehillostt
  3. 扩展题
    1. 第一题
      • 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
      • 使用TreeSet进行排序
    2. 第二题
      • 思考, 能不能将HashSet集合可以存储重复元素(同一个对象)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值