1.简述
Set接口和List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
特点:
- 存入顺序和取出顺序不一致,不保证顺序不变,且元素唯一,底层由HashMap实现。
Set接口中有以下几个常用实现类:
- HashSet:无序并且性能比TreeSet高效,适用于基本的添加、查询元素的场合。
- TreeSet:采用的二叉树的数据结构,需要采用红黑树算法维护数据的排序,对Set的数据类型有要求(需要实现Comparable接口或者是在TreeSet构造的时候定义排序),性能较HashSet低效,比较适用于需要保持排序的场景。
- LinkedHashSet:采用的链表维护插入元素的顺序,其他与HashSet无太大差异,性能较HashSet略低(链表开销)。
- EnumSet:这四种常见Set实现类中最高效的,采用的是位向量的数据结构存储元素(存储高效、紧凑),要求存储元素必须是一个Enum(约束大),适用于枚举值执行批量操作的场景。
2.HashSet
该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。对于HashSet而言,HashSet继承自AbstractSet,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素。因此HashSet的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap 的相关方法来完成。
定义一个HashSet的方式有如下几种:
//构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。 Set<String> set = new HashSet<String>(); //构造一个包含指定 collection 中的元素的新 set。 set = new HashSet<String>(new ArrayList<String>()); //构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。 set = new HashSet<String>(30); //构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。 set = new HashSet<String>(30, 1.2f);
HashSet有很多常用方法,add、addAll、remove、clear、size、isEmpty等,关于其他方法可以查看API。
HashSet的遍历方式和ArrayList一样,这里就不在陈述了。
3.TreeSet
TreeSet是一个有序的集合,它的作用是提供有序的Set集合。它继承了AbstractSet抽象类,实现了NavigableSet<E>,Cloneable,Serializable接口。TreeSet是基于TreeMap实现的,TreeSet的元素支持2种排序方式,自然排序或者根据提供的Comparator进行排序。
定义一个TreeSet的方式有如下几种:
//默认构造函数。使用该构造函数,TreeSet中的元素按照自然排序进行排列。 Set<String> set = new TreeSet<String>(); //创建的TreeSet包含collection set = new TreeSet<String>(new ArrayList<String>()); //指定TreeSet的比较器 set = new TreeSet<String>(new Comparator<String>() { public int compare(String o1, String o2) { int num = o1.compareTo(o2); //比较内容为主要条件 return num == 0 ? 1 : num; //保留重复 } }); //创建的TreeSet包含set SortedSet<String> sortedTreeSet = new TreeSet<String>(); set = new TreeSet<String>(sortedTreeSet);
TreeSet有很多常用方法,add、addAll、remove、clear、size、isEmpty等,关于其他方法可以查看API。
TreeSet的遍历方式和ArrayList一样,这里就不在陈述了。
4.LinkedHashSet
相对HashSet来说,LinkedHashSet存储结构是一个双向链表,因此它存储的元素是有序的。LinkedHashSet继承自HashSet,源码更少、更简单,唯一的区别是LinkedHashSet内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的。
定义一个LinkedHashSet的方式有如下几种:
//默认构造函数 Set<String> set = new LinkedHashSet<String>(); //创建的LinkedHashSet包含容量初始化 set = new LinkedHashSet<String>(30); //创建的LinkedHashSet包含容量和填充比初始化 set = new LinkedHashSet<String>(30, 12.5f); //将其他类型的集合转为LinkedHashSet set = new LinkedHashSet<String>(new ArrayList<String>());
LinkedHashSet有很多常用方法,add、addAll、remove、clear、size、isEmpty等,关于其他方法可以查看API。
LinkedHashSet的遍历方式和ArrayList一样,这里就不在陈述了。
5.EnumSet
EnumSet是一个专为枚举设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。EnumSet的集合元素是有序的,并且不允许加入null元素。EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。
EnumSet是抽象类,只能通过静态工厂方法构造EnumSet对象,具体如下:
- EnumSet<E> noneOf(Class<E> elementType):构造一个空的集合
- EnumSet<E> allOf(Class<E> elementType):构造一个包含枚举类中所有枚举项的集合
- EnumSet<E> of(E e):构造包含1个元素的集合
- EnumSet<E> of(E e1, E e2):构造包含2个元素的集合
- EnumSet<E> of(E e1, E e2, E e3):构造包含3个元素的集合
- EnumSet<E> of(E e1, E e2, E e3, E e4):构造包含4个元素的集合
- EnumSet<E> of(E e1, E e2, E e3, E e4, E e5):构造包含5个元素的集合
- EnumSet<E> of(E first, E... rest):构造包含多个元素的集合(使用可变参数)
- EnumSet<E> copyOf(EnumSet<E> s):构造包含参数中所有元素的集合
- EnumSet<E> copyOf(Collection<E> c):构造包含参数中所有元素的集合
EnumSet有很多常用方法,add、addAll、remove、clear、size、isEmpty等,关于其他方法可以查看API。
EnumSet的遍历方式和ArrayList一样,这里就不在陈述了。