Set的元素重复是如何判断的

相关链接:http://hi.baidu.com/gabe2008/blog/item/eb0448da41d14168d1164e6f.html

当我看到这个问题:Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
         比较标准的说法:Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。

        而我的研究生同学居然说,判断是否重复是由系统内部实现的,他一时半会儿无法理解一个类还须重写equals来判断是否重复。我解释得已经蛮清楚,大体说法,与上一致,但他只接受代码层次的解释,那我对于以前写的TreeSetTest这个类进行简单的修改,才发现,我本不应该拿TreeSet这么特殊的类进行打比方,虽然它也继续于Set接口。

       Set<Cat> set = new TreeSet<Cat>();
      Cat a = new Cat("Qi");
      Cat b = new Cat("Qi");

       代码到这里已经编译报错了?因为,TreeSet是排序的集合,被排序的元素必须实现Comparable接口,那么实现呗。事实上,这里是运行时出错(ClassCastException,而不是编译期的错误。如果TreeSet的构造方法原型内是这个造型:Comparable<? super T>,那么会在编译检错,而Arrays.sort(E, Comparator<? super T> c),那会是如果没有实现Comparator的对象当做排序器,那么编译出错。原本JDK可以使用 class TreeSet<E extends Comparable>,这样的话就能在编译时候做检查。这样的话,就有了矛盾:那些没实现Comparable但是靠Comparator的机制就不行了。

        class Cat implements Comparable 接口,那么按eclipse系统提示,一律返回1,我重写了Cat中的equals方法,用来说明如果Cat的name是一样的话,就返回true,按照我的设想,此TreeSet添加这个元素的时候一定不成功,可是遍历以后,发现它还是添加了两个"Qi",检索才知道,原来TreeSet是用Comparable的方法compareTo的返回值,完整代代码如下:

import java.util.*;

public class TreeSetTest {
   public static void main(String[] args) {
      Set<Cat> set = new TreeSet<Cat>();
     
      set.add(new Cat("Cat1"));
      set.add(new Cat("Cat2"));
      set.add(new Cat("Cat"));
      set.add(new Cat("Cat"));
      set.add(new Cat("Cat"));    //无法被成功添加,因为compareTo的结果是0,Cat name相同
      Iterator<Cat> it = set.iterator();
      while(it.hasNext()){
         System.out.println(it.next().name+":");
      }
   }
}

class Cat implements Comparable{
   public String name;
   public Cat(String name){
      this.name = name;
   }
   public int compareTo(Object o) {
      String name = ((Cat)o).name;
      return this.name.compareTo(name);
   }
}

       这里我们走一个极端,把compareTo的方法返回值一律为return 0; 那么只会添加第一个元素。如以下代码所示:

import java.util.Iterator;
import java.util.TreeSet;

class Drink implements Comparable<Object>{
   public String name;
   public int compareTo(Object o){
      return 0;
   }
}

public class TreeSetDrink {
   public static void main(String[] args) {
      Drink one = new Drink();
      Drink two = new Drink();
      one.name = "Coffee";
      two.name = "Tea";   //因为compareTo返回为0,添加不成功,当成重复元素。
      TreeSet set = new TreeSet();
      set.add(one);
      set.add(two);
      Iterator iterator = set.iterator();
      while(iterator.hasNext()){
         System.out.println(((Drink)iterator.next()).name);   //输出只有Coffee
      }
   }

        再就是想到Set另一个重要子类HashSet,这个集合类继承于Set接口,爷爷是Collection接口,与HashMap没有什么直系血缘关系。首先他接受一个参数的泛型,泛型的作用就是在编译期去严格检查输入类型,HashSet添加元素时,需要对这个泛型类的hashCode值进行判断,测试是否为重复元素,代码如下:

import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;

public class HashSetTest {
   public static void main(String[] args) {
      Set<Pig> hashset = new HashSet<Pig>();
      hashset.add(new Pig("X"));
      hashset.add(new Pig("Y"));
      hashset.add(new Pig("X"));
      Iterator<Pig> iterator = hashset.iterator();
      while(iterator.hasNext()){
         System.out.println(iterator.next().name);
      }
   }
}

class Pig{
   public String name;
   public Pig(String name){
      this.name = name;
   }
  
   public boolean equals(Object o){ //如果不重写,那么所有的new Pig都会被加入,因为hashCode的默认是每个对象惟一的,与equals继承与Object,eqauls在那个阶段与==无异
      String name = ((Pig)o).name;
      if(this.name.equals(name)){
         return true;
      }else
         return false;
   }
  
   public int hashCode(){    //重复测试,首先测试hashCode值,如果一样,再测试equals结果。
       return 0;    //这里只是测试方便这么写了,事实上,如果这么写,是没有任何存储效率的。
   }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值