1. 这些`Set`实现分为通用实现和专用实现。

通用Set实现

[Set](https://docs.oracle.com/javase/8/docs/api/java/util/Set.html)有三种通用的实现—— HashSetTreeSetLinkedHashSet。通常使用这三个中的哪一个很简单。HashSet速度比TreeSet(大多数操作的恒定时间与日志时间)快得多,但不提供排序保证。如果需要使用SortedSet接口中的操作,或者需要按值排序的迭代,请使用TreeSet;否则,请使用HashSet。可以肯定的是,大多数情况下您都会使用HashSet
LinkedHashSet在某种意义上介于HashSetTreeSet之间。作为哈希表实现,并在其中运行链表,它提供了插入顺序的迭代(最近插入的到最新插入的),并且运行速度几乎与HashSet相同。LinkedHashSet实现使客户免于HashSet提供的未指定的,通常混乱的排序,而不会导致与TreeSet关联的成本增加。
关于HashSet值得牢记的一件事是,迭代在条目数和存储桶数(容量)的总和中是线性的。因此,选择过高的初始容量会浪费空间和时间。另一方面,选择过低的初始容量会在每次被迫增加容量时复制数据结构,从而浪费时间。如果未指定初始容量,则默认值为16。过去,选择素数作为初始容量有一些好处。这不再是事实。在内部,容量始终四舍五入为2的幂。初始容量是通过使用int构造函数指定的。下面的代码行分配一个初始容量为64的HashSet

  1. Set<String> s = new HashSet<String>(64);

HashSet类还有另一个调整参数,称为负载系数。 如果您非常在意HashSet的空间消耗,请阅读HashSet文档以获取更多信息。 否则,只需接受默认值即可; 这几乎总是正确的做法。
如果您接受默认的负载系数,但要指定初始容量,则选择一个数字,该数字大约是您希望集合增长大小的两倍。如果您的猜测还遥遥无期,那么您可能会浪费一些空间,时间或两者兼而有之,但这不太可能成为一个大问题。
LinkedHashSet具有与HashSet相同的调整参数,但是迭代时间不受容量影响。TreeSet没有调整参数。

专用Set实现

  1. 有两个特殊用途的`Set`实现—— [`EnumSet`](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html)和 [`CopyOnWriteArraySet`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArraySet.html)。<br />`EnumSet`是`Set`枚举类型的高性能实现。枚举集的所有成员必须具有相同的枚举类型。在内部,它由位向量表示,通常为单个`long`。枚举集支持在枚举类型范围内进行迭代。例如,给定枚举声明为星期几,则可以在工作日中进行迭代。`EnumSet`类提供了一个易于使用的静态工厂。
  1. for (Day d : EnumSet.range(Day.MONDAY, Day.FRIDAY))
  2. System.out.println(d);
  1. 枚举集还为传统的位标志提供了丰富的类型安全替代。
  1. EnumSet.of(Style.BOLD, Style.ITALIC)

CopyOnWriteArraySet是由写时复制数组备份的Set实现。所有可变操作,如addset,和remove,通过使所述数组的一个新的复制来实现; 无需锁定。甚至迭代也可以安全地与元素插入和删除同时进行。不像大多数Set实现中,addremove,和contains方法需要的时间与集合的大小。此实现适用于很少修改但经常迭代的集合。它非常适合维护必须防止重复的事件处理程序列表。