分类: Java
2012-02-23 12:52:35
一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。
//重写equals时hashCode方法也要重写集合中两个对象比较的顺序:先调用hashCode(),然后调用equals();
//hashCode相等时,继续调用equals,表示两个对象可能相等可能不相等;
//不相等时不调用equals,表示两个对象一定不相等;
}
public class HashSet
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
此类为基本操作提供了稳定性能,这些基本操作包括 add、remove、contains 和 size,假定哈希函数将这些元素正确地分布在桶中。对此 set 进行迭代所需的时间与 HashSet 实例的大小(元素的数量)和底层 HashMap 实例(桶的数量)的“容量”的和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到 set s 中。)
此实现可以让客户免遭未指定的、由 提供的通常杂乱无章的排序工作,而又不致引起与 关联的成本增加。使用它可以生成一个与原来顺序相同的 set 副本,并且与原 set 的实现无关:
void foo(Set s) { Set copy = new LinkedHashSet(s); ... } 如果模块通过输入得到一个 set,复制这个 set,然后返回由此副本决定了顺序的结果,这种情况下这项技术特别有用。(客户通常期望内容返回的顺序与它们出现的顺序相同。)此类提供所有可选的 Set 操作,并且允许 null 元素。与 HashSet 一样,它可以为基本操作(add、contains 和 remove)提供稳定的性能,假定哈希函数将元素正确地分布到存储段中。由于增加了维护链接列表的开支,其性能很可能会比 HashSet 稍逊一筹,不过,这一点例外:LinkedHashSet 迭代所需时间与 set 的大小 成正比,而与容量无关。HashSet 迭代很可能支出较大,因为它所需迭代时间与其容量 成正比。
链接的哈希 set 有两个影响其性能的参数:初始容量 和加载因子。它们与 HashSet 中的定义极其相同。注意,为初始容量选择非常高的值对此类的影响比对 HashSet 要小,因为此类的迭代时间不受容量的影响。
基于 的 实现。使用元素的对元素进行排序,或者根据创建 set 时提供的 进行排序,具体取决于使用的构造方法。
此实现为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销。
注意,如果要正确实现 Set 接口,则 set 维护的顺序(无论是否提供了显式比较器)必须与 equals 一致。为了保证TreeSet能正确的排序,要求类的compareTo方法与equals方法按相同的规则比较类的对象。也就是说,如果equals方法返回true,那么compareTo方法返回值为0。这个只是为了统一对象的比较方法(关于与 equals 一致 的精确定义,请参阅 Comparable 或 Comparator。)这是因为 Set 接口是按照 equals 操作定义的,但 TreeSet 实例使用它的 compareTo(或 compare)方法对所有元素进行比较,因此从 set 的观点来看,此方法认为相等的两个元素就是相等的。即使 set 的顺序与 equals 不一致,其行为也是 定义良好的;它只是违背了 Set 接口的常规协定。
该程序的一次执行结果为:
第 0 次随机数产生为:96
第 1 次随机数产生为:64
第 2 次随机数产生为:14
第 3 次随机数产生为:95
第 4 次随机数产生为:57
未排序前HashSet:[64, 96, 95, 57, 14]
未排序前LinkedHashSet:[96, 64, 14, 95, 57]
排序后 TreeSet :[14, 57, 64, 95, 96]
从这个例子中,我们可以知道HashSet的元素存放顺序和我们添加进去时候的顺序没有任何关系,而LinkedHashSet 则保持元素的添加顺序。TreeSet则是对我们的Set中的元素进行排序存放。
一般来说,当您要从集合中以有序的方式抽取元素时,TreeSet 实现就会有用处。为了能顺利进行,添加到 TreeSet 的元素必须是可排序的。 而您同样需要对添加到TreeSet中的类对象实现 Comparable 接口的支持。一般说来,先把元素添加到 HashSet,再把集合转换为 TreeSet 来进行有序遍历会更快。这点和HashMap的使用非常的类似。
其实Set利用的就是Map中“键”不能重复的特性来实现的。