Set集合
Set集合类似于一个罐子,程序可以依次把多个对象“丢进”Set集合,而Set集合通常不能记住元素的添加顺序。实际上Set就是Collection只是行为略有不同(Set不允许包含重复元素)。
- Set集合不允许包含相同的元素,如果试图把两个相同元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。
- Set集合,继承自Collection。特征是插入无序,不可指定位置访问。
- Set集合的实现类可说是基于Map集合去写的。通过内部封装Map集合来实现的。比如HashSet内部封装了HashMap。
- Set集合的数据库不能重复(== 或 eqauls)的元素。
- Set集合的常用实现类有 HashSet、TreeSet
HashSet类(多线程不安全)
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时就是使用这个实现类。HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。底层数据结构是哈希表。
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化;
- HashSet不是同步的;
- 集合元素值可以是null;
哈希表: 一个元素为链表的数组,综合了数组与链表的优点。
当向 HashSet 集合中存入一个元素时,HashSet会调用该对象的hashCode方法来得到该对象的hashCode值,然后根据该hashCode值决定该对象在HashSet中的存储位置。
- 如果有两个元素通过equals方法比较true,但它们的hashCode方法返回的值不相等,HashSet将会把它们存储在不同位置,依然可以添加成功。
- 也就是说。HashSet集合判断两个元素的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。即:靠元素重写hashCode方法和equals方法来判断两个元素是否相等,如果相等则覆盖原来的元素,以此来确保元素的唯一性。
HashSet的优势
- 因为数组的索引是连续的而且数组的长度是固定的,无法自由增加数组的长度。而HashSet就不一样了,HashCode表用每个元素的hashCode值来计算其存储位置,从而可以自由增加HashCode的长度
- 并根据元素的hashCode值来访问元素。而不用一个个遍历索引去访问,这就是它比数组快的原因。
- HashCode中每个存储元素的“槽位”通常称为“桶”,如果多个元素的hashCode值相同,但它们通过equals方法比较返回false,就需要在桶里放多个元素,这样会导致性能下降。
LinkedHashSet类
HashSet 还有一个子类 LinkedList、LinkedHashSet 集合也是根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的,也就是说当遍历集合 LinkedHashSet 集合里的元素时,集合将会按元素的添加顺序来访问集合里的元素。
输出集合里的元素时,元素顺序总是与添加顺序一致。但是LinkedHashSet 依然是 HashSet,因此它不允许集合重复。
TreeSet类
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
内部存储机制
TreeSet内部实现的是红黑树,默认整形排序为从小到大。
EnumSet类
EnumSet类的特征:
- EnumSet是一个专门为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。
- EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
- EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。
- EnumSet集合不允许加入null元素。
- EnumSet类没有暴露任何构造器来创建该类的实例,
EnumSet 类提供了以下类方法来创建 EnumSet 对象。
- EnumSet allOf(Class elementType):创建一个包含指定枚举类里所有枚举值的 EnumSet 集合。
- EnumSet complementOf(EnumSet s):创建一个其元素类型与指定EnumSet里元素类型相同的 EnumSet 集合,新的集合里包含原集合不包含的枚举值。
- EnumSet copyOf(Collection c):使用一个普通集合来创建 EnumSet 集合;
- EnumSet copyOf(EnumSet s):复制原集合;
- EnumSet noneOf(Class elementType):创建一个元素类型为指定枚举类型的空EnumSet;
- EnumSet of(E first,E…rest):创建一个包含一个或多个枚举值的EnumSet集合。传入的枚举值必须是同一枚举类。
- EnumSet range(E from,E to):创建一个包含从 from 到 to 枚举值范围所有枚举值的 EnumSet 集合。
package com.collection;
import java.util.EnumSet;
public class EnumSetTest {
public static void main(String[] args) {
//1.创建一个包含Session(枚举类)里所有枚举值的EnumSet集合
EnumSet e1 = EnumSet.allOf(Session.class);
System.out.println(e1);//[SPRING, SUMMER, FAIL, WINTER]
//2.创建一个空EnumSet
EnumSet e2 = EnumSet.noneOf(Session.class);
System.out.println(e2);//[]
//3. add()空EnumSet集合中添加枚举元素
e2.add(Session.SPRING);
e2.add(Session.SUMMER);
System.out.println(e2);//[SPRING, SUMMER]
//4. 以指定枚举值创建EnumSet集合
EnumSet e3 = EnumSet.of(Session.SPRING,Session.FAIL);
System.out.println(e3);//[SPRING, FAIL]
//5.创建一个包含从from枚举值到to枚举值范围内所有枚举值的EnumSet集合。
EnumSet e4 = EnumSet.range(Session.SPRING,Session.FAIL);
System.out.println(e4);//[SPRING, SUMMER, FAIL]
//6.创建一个其元素类型与指定EnumSet里元素类型相同的EnumSet集合,
// 新EnumSet集合包含原EnumSet集合所不包含的枚举值
EnumSet e5 = EnumSet.complementOf(e4);
System.out.println(e5);//[WINTER]
}
}
//创建一个枚举
enum Session{
SPRING,
SUMMER,
FAIL,
WINTER
}