前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【java筑基】一篇教会你set集合

【java筑基】一篇教会你set集合

作者头像
用户10127530
发布2022-10-26 18:39:58
2530
发布2022-10-26 18:39:58
举报
文章被收录于专栏:半旧的技术栈半旧的技术栈

前 言 🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:深入、全面、系统的介绍java的基础知识 🌰 文章简介:本文将介绍java常用的set集合,建议收藏备用,创作不易,敬请三连哦 🍎大厂真题:大厂集合面试题汇总

文章目录

Set集合与Collection基本相同,具有一些不同的行为。Set集合中的元素是无序的,不可以重复添加元素。

1 HashSet类

集合值可以为null,不是同步的,元素是无序的,通过哈希算法计算元素存储的位置,因而可以自动增加其容量。HashSet中元素使用的槽位是“桶‘,如果两个对象的equals()方法返回值是true,会放在一个桶里,通过链式方法存储。因此最好避免出现不同对象equals方法返回true的情况,防止性能下降。

如果把一个对象放入HashSet集合中,重写equals()方法时,也应该重写hashcode()方法。规则是:如果两个对象的equals()返回值是true,则hashcode值应该相同。重写hashcode()方法的步骤是:1.根据规则计算每个实例变量的hashcode值 2.各个实例变量乘以一个质数加权相加。

如果是可变对象,后面的Java程序改变该对象,使该对象中实例变量与另一个对象相同,就可能导致两个对象的hashcode值相同。这会导致HashSettings发生混乱,这个被修改了的对象无法访问了(无法计算hashcode找到它的真实位置了)。当我们把一个元素装入HashSet集合中后,尽量不要修改参与计算hashcode值的实例变量。

LinkedHashSet类是HashSet类的子类,在物理上是根据hash算法存储元素,但是还通过链表方式来维护其元素顺序。

2 TreeSet类

TreeSet类是SorttedSet接口的实现类。其元素是排序(按大小)的。

代码语言:javascript
复制
    public class TreeSetTest {
    	public static void main(String[] args) {
    		TreeSet nums = new TreeSet();
    		nums.add(5);
    		nums.add(2);
    		nums.add(10);
    		nums.add(-9);
    		// [-9, 2, 5, 10]
    		System.out.println(nums);
    		System.out.println(nums.first());
    		// 返回小于4的子集 [-9, 2]
    		System.out.println(nums.headSet(4));
    		// [5, 10]
    		System.out.println(nums.tailSet(5));
    		//[2]
    		System.out.println(nums.subSet(-3, 4));
    	}
    }

TreeSet是通过调用集合元素的commpareTo(Object obj)方法比较元素的大小关系。如果试图把一个对象添加到TreeSet时,则该对象必须实现Comparable接口,否则会抛出异常。

代码语言:javascript
复制
    class Err {
    }
    
    public class TreeSetErrorTest {
    	public static void main(String[] args) {
    		TreeSet ts = new TreeSet();
    		ts.add(new Err());
    		//添加第二个元素时自动调用compareTo()反复,引发ClassCastException
    		ts.add(new Err());
    	}
    }
    ```

TreeSet中元素的比较完全是基于compareTo()方法来进行的。
```java
    class Z implements Comparable {
    	int age;
    
    	public Z(int age) {
    		this.age = age;
    	}
    
    	public int compareTo(Object o) {
    		return 1;
    	}
    
    	public boolean equals(Object o) {
    		return true;
    	}
    
    	@Override
    	public String toString() {
    		return "Z [age=" + age + "]";
    	}
    }
    
    public class TreeSetTest2 {
    	public static void main(String[] args) {
    		TreeSet ts = new TreeSet();
    		Z z1 = new Z(6);
    		ts.add(z1);
    		// 打印true,即使是同一个对象,但由于compareTo()方法的返回值是1,仍然可以添加
    		System.out.println(ts.add(z1));
    		// [Z [age=6], Z [age=6]]
    		System.out.println(ts);
    		((Z) ts.first()).age = 9;
    		//[Z [age=9], Z [age=9]]
    		System.out.println(ts);
    	}
    }

TreeSet中的对象存储可参考下图

在这里插入图片描述
在这里插入图片描述

但是如果一个可变的对象放入TreeSet中后,该对象的实例变量如果在后续代码中改变了,TreeSet不会再调整它们的顺序。该元素也无法被删除了(甚至与该元素值相同的未被修改的元素也无法被删除)。

可以通过Coparator自定义TreeSet的比较规则。

代码语言:javascript
复制
    class M {
    	int age;
    
    	public M(int age) {
    		this.age = age;
    	}
    
    	@Override
    	public String toString() {
    		return "M [age=" + age + "]";
    	}
    
    }
    
    public class TreeSetTest3 {
    	public static void main(String[] args) {
    		// 此处Lambda表达式的目标类型是comparator
    		TreeSet ts = new TreeSet((o1, o2) -> {
    			M m1 = (M) o1;
    			M m2 = (M) o2;
    			return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0;
    		});
    		ts.add(new M(5));
    		ts.add(new M(-3));
    		ts.add(new M(4));
    		//[M [age=5], M [age=4], M [age=-3]]
    		System.out.println(ts);
    	}
    }

3 EnumSet类

EnumSet类专门为枚举类型数据设计,在内部以位向量形式存储数据,这种高效的存储方式使EnumSet对象占用内存小,效率高(尤其是在进行批处理时)。EnumSet中不允许加入null值,否则会报出空指针异常。

代码语言:javascript
复制
    enum Season {
    	SPRING, SUMMER, FALL, WINTER
    }
    
    public class EnumSetTest {
    	public static void main(String[] args) {
    		EnumSet es1 = EnumSet.allOf(Season.class);
    		System.out.println(es1);
    
    		EnumSet es2 = EnumSet.noneOf(Season.class);
    		// []
    		System.out.println(es2);
    
    		es2.add(Season.WINTER);
    		System.out.println(es2);
    	}
    }

4 各Set类的性能分析

HashSet在查找、增加数据时性能都要比TreeSet更好,这是因为TreeSet底层要通过红黑树来维护,只有需要保持排序的存储元素时才选用TreeSet。LinkedHashSet在增加、删除元素时,比HashSet略慢,这是链表造成的开销,但是由于链表结构,LinkedHashSet会在遍历上更快。EnumSet是所有Set中性能最好的,但是只能存储枚举类型数据。Set集合都是线程非安全的,可以使用collections工具类中sychronizedSortedSet方法包装该集合来实现同步。

代码语言:javascript
复制
    SortedSet s=Collections.synchronizedSortedSet(new TreeSet());

这篇set集合的内容就介绍到这里结束了,学习集合建议适当刷题,这里给推荐一个大厂刷题网站:牛客网|大厂面试笔试真题汇总

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 1 HashSet类
  • 2 TreeSet类
  • 3 EnumSet类
  • 4 各Set类的性能分析
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档