Set 如何比较重复元素

HashSet部分: 

   以下以HashSet为例进行分析。 
   从Hashset类的主体部分: 
public class HashSet<E> extends AbstractSet<E> 
     implements Set<E>, Cloneable, java.io.Serializable 

  static final long serialVersionUID = -5024744406713321676L; 
  private transient HashMap<E,Object> map; 
  // Dummy value to associate with an Object in the backing Map 
  //这是每个键所指的对像 
  private static final Object PRESENT = new Object(); 


     public HashSet() { 
   map = new HashMap<E,Object>(); 
      } 
     public boolean add(E o) { 
   return map.put(o, PRESENT)==null; 
      } 
    //以下省略.......... 
    } 

        public HashSet() { 

  map = new HashMap<E,Object>(); 
    

   可以看到HashSet使用了HashMap作为其Map保存“键-值”对。 
   
   请看示例程序4: 
import java.util.*; 

public class SetTest4 { 
public static void main(String[] args){ 
  Set set = new HashSet(); 
  set.add(new SetElement4("aa")); 
  set.add(new SetElement4("aa")); 
  set.add(new SetElement4("bb")); 
  System.out.println(set); 

static class SetElement4{ 
  String s; 
  public SetElement4(String s){ 
   this.s =  s; 
  } 
  public String toString(){ 
   return s; 
  } 
  public boolean equals(Object obj) { 
   return s.equals(((SetElement4)obj).s); 
  } 



   运行结果: 
   [bb, aa, aa] 
   没有“示例程序1”中的java.lang.ClassCastException,但是运行结果似乎不对,因为有两个“aa”。 
   
   请看示例程序5: 
import java.util.*; 
public class SetTest5 { 
  public static void main(String[] args){ 
   Set set = new HashSet(); 
   set.add(new SetElement5("aa")); 
   set.add(new SetElement5("aa")); 
   set.add(new SetElement5("bb")); 
   System.out.println(set); 
  } 
  static class SetElement5{ 
   String s; 
   public SetElement5(String s){ 
    this.s =  s; 
   } 
   public String toString(){ 
    return s; 
   } 
   public boolean equals(Object obj) { 
    return s.equals(((SetElement5)obj).s); 
   } 
   public int hashCode() { 
    //return super.hashCode(); 
    return s.hashCode(); 
   } 
  } 

    运行结果: 
    [bb, aa] 
    这就对了。“示例程序4”和“示例程序5”有什么区别?是SetElement5重写了hashCode方法。 
    
    可见HashSet中是采用了比较元素hashCode的方法来判断元素是否相同(duplicate),而不是采用其他类似equals之类的东东来判断。 
    
    说了这么多,那java类库中到底有没有根据equals来判断元素是否相同(duplicate)的Set呢?请看下文。 
2.2、CopyOnWriteArraySet部分: 
   类CopyOnWriteArraySet是java.util.concurrent包中的一个类,所以它是线程安全的。 
   CopyOnWriteArraySet是使用CopyOnWriteArrayList作为其盛放元素的容器。当往CopyOnWriteArrayList添加新元素,它都要遍历整个List,并且用equals来    比较两个元素是否相同。 

   请看示例程序6: 
import java.util.*; 
import java.util.concurrent.*; 
public class SetTest6 { 
  public static void main(String[] args){ 
   Set set = new CopyOnWriteArraySet(); 
   set.add(new SetElement6("aa")); 
   set.add(new SetElement6("aa")); 
   set.add(new SetElement6("bb")); 
   System.out.println(set); 
  } 
  static class SetElement6{ 
   String s; 
   public SetElement6(String s){ 
    this.s =  s; 
   } 
   public String toString(){ 
    return s; 
   } 
   public boolean equals(Object obj) { 
    return s.equals(((SetElement6)obj).s); 
   } 
  } 

   运行结果: 
   [aa, bb] 
   好了,一切搞定!! 

3、总结: 
   Javadoc中的一些描述可能是不准确的,大家要当心了! 
   
   Set中实现元素互异的各种方法差异很大,大致可以分为三种:使用equals,使用hashCode,使用compareTo。但是我还没有发现采用“判断地址空间是否相同”来判断元素是否相同的类,当然我们可以用现有的三种方法来实现“判断地址空间是否相同”。 
   
   综上所述,我们可以总结出使用Set的三种不同的情形:(以下假设元素类为Element) 
   A、如果想使用Element的equals方法来判断元素是否相同,那么可以使用CopyOnWriteArraySet来构造类的实体。 
   B、如果Element实现了Comparable接口,而且想使用compareTo方法来判断元素是否相同,那么可以使用TreeSet来构造类的实体。 
   C、如果想使用判断hashCode是否相同的方法来判断元素是否相同,那么可以使用HashSet来构造类的实体

发表于 @ 2009年12月17日 17:


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/pss360/archive/2009/12/17/5026516.aspx

你可能感兴趣的:(set)