Chinaunix首页 | 论坛 | 博客
  • 博客访问: 752735
  • 博文数量: 130
  • 博客积分: 2951
  • 博客等级: 少校
  • 技术积分: 1875
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 18:32
文章分类

全部博文(130)

文章存档

2013年(1)

2012年(129)

分类: Java

2012-02-23 12:52:35

public interface Setextends

一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。

  1. package intro.collections;

  2. import java.util.HashSet;
  3. import java.util.Set;
  4. class Test1{
  5.     public String name;
  6.     public Test1(String name){
  7.         this.name = name;
  8.     }
  9.     @Override
  10.     public boolean equals(Object o){
  11.         Test1 obj = (Test1)o;
  12.         return this.name == obj.name;
  13.     }
  14.     @Override
  15.     public int hashCode(){
  16.         int result = 17;
  17.         result = 37 * result + this.name.hashCode();
  18.         return result;
  19.     }

//重写equals时hashCode方法也要重写集合中两个对象比较的顺序:先调用hashCode(),然后调用equals();
//hashCode相等时,继续调用equals,表示两个对象可能相等可能不相等;

//不相等时不调用equals,表示两个对象一定不相等;

}


  1. public class SetTest {
  2.     public static void main(String [] args){
  3.         Set<Test1> set = new HashSet<Test1>();
  4.         Test1 t1 = new Test1("zhang");
  5.         Test1 t2 = new Test1("wang");
  6.         set.add(t1);
  7.         set.add(t2);
  8.         System.out.println(set); //输出[intro.collections.Test1@6e7f661, intro.collections.Test1@379478] 
  9.         Test1 t3 = new Test1("zhang");
  10.         set.add(t3);
  11.         System.out.println(set); //仍然输出[intro.collections.Test1@6e7f661, intro.collections.Test1@379478]
  12.     }
  13. }

public class HashSetextends implements , ,

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

此类为基本操作提供了稳定性能,这些基本操作包括 add、remove、contains 和 size,假定哈希函数将这些元素正确地分布在桶中。对此 set 进行迭代所需的时间与 HashSet 实例的大小(元素的数量)和底层 HashMap 实例(桶的数量)的“容量”的和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。


public class LinkedHashSetextends implements , ,

具有可预知迭代顺序的 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 要小,因为此类的迭代时间不受容量的影响。


public class TreeSetextends implements , ,

基于 的 实现。使用元素的对元素进行排序,或者根据创建 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 接口的常规协定。 

  1. import java.util.*;
  2. public class SetSortExample {
  3.   public static void main(String args[]) {
  4.     Set set1 = new HashSet();
  5.     Set set2 = new LinkedHashSet();
  6.     for(int i=0;i<5;i++){
  7.         //产生一个随机数,并将其放入Set中
  8.         int s=(int) (Math.random()*100);
  9.          set1.add(new Integer( s));
  10.          set2.add(new Integer( s));
  11.          System.out.println("第 "+i+" 次随机数产生为:"+s);
  12.     }
  13.     System.out.println("未排序前HashSet:"+set1);
  14.     System.out.println("未排序前LinkedHashSet:"+set2);
  15.     //使用TreeSet来对另外的Set进行重构和排序
  16.     Set sortedSet = new TreeSet(set1);
  17.     System.out.println("排序后 TreeSet :"+sortedSet);
  18.   }
  19. }

该程序的一次执行结果为:

第 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中“键”不能重复的特性来实现的。


阅读(1359) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~