黑马程序员技术交流社区

标题: HashSet与TreeSet的疑问 [打印本页]

作者: 梁志仲    时间: 2012-8-9 19:44
标题: HashSet与TreeSet的疑问
HashSet要确保元素唯一性,是通过判断hashCode的值和equals方法实现的,元素本身应该是具有hashCode的了,为什么我们还要覆写hashCode方法呢?

TreeSet是通过compareTo方法来保证元素是否唯一,那还需不需要覆写hashCode方法和equals方法啊?

一直对这两个集合的特性搞不清楚,请各位赐教。
作者: 戎石锁    时间: 2012-8-9 19:50
HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
                        HashSet是如何保证元素唯一性的呢?
                        是通过元素的两个方法,hashCode和equals来完成。
                        如果元素的HashCode值相同,才会判断equals是否为true。
                        如果元素的hashcode值不同,不会调用equals。
                        注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的                                hashcode和equals方法。
                |--TreeSet:可以对Set集合中的袁术进行排序。底层数据结构是二叉树。
        保证元素的唯一性的依据:compareTo()方法return 0.
        
        TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo()方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。
        
        当元素自身不具备比较性,或者具备的比较性不是所需要的。
        这时需要让容器自身具备比较性。
        定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
        当两种排序都存在时,以比较器为主。
        定义一个类,实现Comparator接口,覆盖compare方法。
作者: 王健    时间: 2012-8-9 19:53
本帖最后由 王健 于 2012-8-9 19:58 编辑

如果LZ你的对象想放到Set集合或者是想作为Map的key时(非散列的Set和Map,例如TreeSet,TreeMap等),那么你必须重写equals()方法,这样才能保证唯一性。当然,在这种情况下,你不想重写hashCode()方法,也没有错。但是,对于良好的编程风格而言,你应该在重写equals()方法的同时,也重写hashCode()方法。
然后再说说必须重写hashCode()的情况:
    如果你的对象想放进散列存储的集合中(比如:HashSet,LinkedHashSet)或者想作为散列Map(例如:HashMap,LinkedHashMap等等)的Key时,在重写equals()方法的同时,必须重写hashCode()方法。

hashCode()方法用来提高效率的,为速度而散列。因为散列的Set和Map是基于hashcode方法来查找对象的,所以你在使用这些类的时候一定要覆盖hashcode方法,而非散列的Set和Map,例如TreeSet,TreeMap等,它们只需equals方法就可以唯一确定对象的身份。

作者: 叶久瑞    时间: 2012-8-9 19:55
本帖最后由 叶久瑞 于 2012-8-9 19:57 编辑

    HashSet_____________________________________________
HashSet:内部实际结构是哈希表,是不同步的。
哈希表:将对象经过哈希算法计算成该对象的哈希值,并把哈希值存放在哈希表中,其实哈希值就相当于数组中的角标。所以在查找的时候直接根据哈希值查询,速度很快。
哈希表确定元素是否相同
        判断的是两个元素的哈希值是否相同,如果相同,再判断两个对象的内容是否相同
        判断哈希值相同,其实判断的是对象的hashcode的方法,判断内容相同,用的是equlas方法
注意:如果哈希值不同,是不用判断equals.
Hahset集合数据是哈希表,所以存储元素的时候,使用的元素的hashcode方法来确定位置,如果位置相同,在通过元素的equals来确定是否相同。也就是通过对象的hashcode和equals方法来完成对象唯一性的,如果对象的hashcode值不同,那么不用判断equals方法,就直接存储到哈希表中,如果对象的hashcode值相同,那么要再次判断对象的equals 方法是否为true,如果为true,视为相同元素,不存,如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到hashset集合中,必须覆盖hashcode方法和equals方法,一般情况下,如果定义的类会产生很多对象,比如人,学生,数,通常都需要覆盖equlas,hashcode方法。建立对象判断是否相同的依据。
____TreeSet_______________________________________
TreeSet:可以对集合中的元素进行排序,是不不同步的,
判断元素唯一性的方式:即使根据比较方法的返回结果是否是0,是0,就是相同的元素,不存,
        Treeset对元素进行排序的方式一:
让元素自身具备比较功能,就需要实现comparable接口,覆盖comparaTo( )方法。如果不要按照对象中具备的自然顺序进行排序,如果对象中不具备自然顺序,怎么办?
        可以使用treeset集合第二种排序方式二:
让集合自身比较功能,定义一个类实现comparator接口,覆盖compare方法。将该类对象作为参数传递给treeset集合的构造函数。

作者: 黑马-刘心武    时间: 2012-8-9 20:03
HashSet底层数据结构是哈希表。是通过元素的hashCode和equals两个方法来保证元素唯一性。如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。
   对象本身已经具备HashCode,但如Student(name01,20)中的name的HashCode和Student(name01,22)中的name的HashCod的值是一样的,默认比较久会认为是同一个人,所以要覆写HashCode方法,如:
        public int hashCode()
                {
                        return name.hashCode()+age*35;
                }
        现在名字的HashCode的值为原来的值加上age*35,这样子如果同名不同年龄的对象就不会被认为是同一对象,所以需要覆盖。
       
        二、TreeSet底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0.
故不用覆盖HashCode和equals方法。

TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法。这方式也成为元素的自然顺序,或者叫做默认顺序。
        class Student implements Comparable   //该接口强制让学生具备比较性。
        {
                public int compareTo(Object obj)   //覆盖compareTo方法
                {
        if(!(obj instanceof Student))
                                throw new RuntimeException("不是学生对象");
                        Student s = (Student)obj;
                        System.out.println(this.name+"....compareto....."+s.name);
                        if(this.age>s.age)
                                return 1;
                        if(this.age==s.age)
                        {
                                return this.name.compareTo(s.name);
                        }
                        return -1;
         }
        }

TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。定义一个比较器类继承Comparator接口,覆盖comper方法,将比较器对象作为参数传递给TreeSet集合的构造函数,就有了比较性。
       
        class myComp implements Comparator    //定义比较器类{
        public int compare(Object o1,Object o2)
        {
        String s1 = (String)o1;
                String s2 = (String)o2;
                int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
                        if(num==0)
                                return s1.compareTo(s2);
                        return num;
        }
        }
    TreeSet ts = new TreeSet(new  myComp());  //在集合声明初始化时传入比较器

作者: 官文昌    时间: 2012-8-9 23:59
是的,它的确有自己的hashcode方法,但是当你输入person对象时,我们把名字相同和年龄相同的看成相同的,你不覆写hshcode方法,它就会把只要是名字相同的都看成是一个人~~hashmap要保证输入对象的唯一性~~所以我们一般要覆写它~~




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2