黑马程序员技术交流社区

标题: 关于HashSet一个问题 [打印本页]

作者: IT人    时间: 2013-11-29 10:30
标题: 关于HashSet一个问题
在重写了equals没有重写hashCode方法的情况下:
Collection  colletions = new HashSet();
ReflectPoint pt1 =  new ReflectPoint(3,3);
ReflectPoint pt2 =  new ReflectPoint(5,5);
ReflectPoint pt3 =  new ReflectPoint(3,3,);

collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);

System.out.println(collections.size());

打印的结果为什么有可能是3,也有可能是2
作者: 刘敏    时间: 2013-11-29 10:49
怎么会有2出现了,我按你的说法把你的代码执行了1000遍,结果只有3.
import java.util.*;

class ReflectPoint
{
        private  int x;
        private  int y;
       
        ReflectPoint(int x, int y)
        {
                this.x = x;
                this.y = y;
        }
        public boolean equals(Object obj)
        {
                ReflectPoint  tmpObj = (ReflectPoint)obj;
                return((this.x == tmpObj.x) && (this.y == tmpObj.y));
        }
}

class CollectionDemo
{

        public static void main(String[] args)
        {
                myTestFunc();
        }
       
        static void myTestFunc()
        {
                for(int i=0; i<1000;i++)
                {
                        Collection  collections = new HashSet();
                        ReflectPoint pt1 =  new ReflectPoint(3,3);
                        ReflectPoint pt2 =  new ReflectPoint(5,5);
                        ReflectPoint pt3 =  new ReflectPoint(3,3);
                       
                        collections.add(pt1);
                        collections.add(pt2);
                        collections.add(pt3);
                        collections.add(pt1);
       
                        System.out.println(collections.size());
                }
        }
}


作者: Jim-剣◆﹏    时间: 2013-11-29 10:56
本帖最后由 Jim-剣◆﹏ 于 2013-11-29 13:59 编辑

这要看你的重写的equals是怎么实现的
你首先得明确hashSet存储去除重复元素的机制:先比较元素的hashCode,如果hashCode相同,则再比较equals,如果hashCode和equals都相同,那么这个元素就不会被添加进集合,如果hashCode不同,则不需要比较equals,直接添加进集合
ReflectPoint pt1 =  new ReflectPoint(3,3);
ReflectPoint pt2 =  new ReflectPoint(5,5);
ReflectPoint pt3 =  new ReflectPoint(3,3,);

pt1,pt2,pt3,没有重写hashCode(),那么他们的hashCode()就是继承父类Object的hashCode()
查看源代码可以知道,父类Object的hashCode()是关联内存地址值的,而pt1,pt2,pt3这三个对象都是通过关键字new出来的,内存地址必定不一样,所以,pt1,pt2,pt3的hashCode()值也必定不一样
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
这三个可以直接添加进集合
对于再写一句collections.add(pt1);
这个当楼主你重写equals是这
  1. public boolean equals(Object obj){

  2.       rerurn false;

  3. }
复制代码

样的时候

此时打印结果是4

当楼主你重写的equals方法关联到对象的属性值时,判断依据是对象的属性时,就不能添加进去
此时打印结果就是3

重点看你怎么实现equals方法

不过一般没人会写一个不做任何比较直接返回boolean值的equals方法,但是是存在这种可能的
--------------------------------------------------------------------------------------------------分割线
以上说法没经过实践仓促回复,后来经过验证,发现了就算在equals中直接返回一个false还是不能成功添加,打印结果还是为3
似乎java有别的机制去除重复元素,并不只是根据hashCode和equals来工作的
故另外开贴咨询大牛,详情请移步http://bbs.itheima.com/forum.php?mod=viewthread&tid=101147&page=1&extra=#pid566897







作者: 李文帅    时间: 2013-11-29 11:52
对于HashSet集合,存放的元素是无序的,并且不允许存放重复元素
当实例化对象时,系统会为每个对象开辟一块空间,每个对象都会有一个hashCode值,而每一个对象的hashCode值是互不相同的
对于楼主的程序ReflectPoint类中
如果未复写hashCode()方法,主函数中实例化对象pt1,pt2,pt3都有各自的hashCode值,并且互不相同,所以执行添加元素操作时pt1,pt2,pt3都成功存入,对于第四个添加操作,由于pt1已存在,所以添加失败,楼主可以添加代码验证:System.out.println(collections.add(pt1));所以打印结果是3
如果复写了hashCode方法,主函数中实例化对象pt1和pt3指向同一个对象,所以集合中成功添加的元素只有两个,所以打印结果是2
下面是我写的代码:
  1. import java.util.*;


  2. public class Foo {
  3.         public static void main(String[] args) {
  4.                 Collection  collections = new HashSet();
  5.                 ReflectPoint pt1 =  new ReflectPoint(3,3);
  6.                  ReflectPoint pt2 =  new ReflectPoint(5,5);
  7.                  ReflectPoint pt3 =  new ReflectPoint(3,3);

  8.                  System.out.println(collections.add(pt1));
  9.                  System.out.println(collections.add(pt2));
  10.                  System.out.println(collections.add(pt3));
  11.                  //由于pt1在集合中已存在,所以打印结果是false,即添加失败
  12.                  System.out.println(collections.add(pt1));

  13.                  System.out.println(collections.size());
  14.         }
  15. }
  16. class ReflectPoint{
  17.         private int x;
  18.         private int y;
  19.         /*
  20.         public int  hashCode(){
  21.                 return x + y*39;
  22.         }
  23.         如果未复写hashCode(),则pt1和pt3的hashCode值是不同的,
  24.         则System.out.println(collections.add(pt3));打印结果是true,即添加成功
  25.         所以集合中只添加了三个元素
  26.         如果复写hashCode(),则pt1和pt3的hashCode值是相同的,
  27.         则System.out.println(collections.add(pt3));打印结果是false,即添加失败
  28.         所以集合中只添加了两个元素
  29.        
  30.         */
  31.         public ReflectPoint(int x,int y){
  32.                 this.x = x;
  33.                 this.y = y;
  34.         }
  35.         public int getX(){
  36.                 return x;
  37.         }
  38.         public int getY(){
  39.                 return y;
  40.         }
  41.         public boolean equals(Object obj){
  42.                 if(!(obj instanceof ReflectPoint))
  43.                         throw new ClassCastException("类型不匹配!");
  44.                 ReflectPoint r = (ReflectPoint)obj;
  45.                 return this.x==r.x && this.y==r.y;
  46.         }
  47. }
复制代码

这是我个人的理解,希望能够帮得到你
作者: IT人    时间: 2013-11-29 16:03
听教程!上面说可能出现2,可是我也执行了几遍!但是还是3,谢谢了!
作者: 简★零度    时间: 2013-11-30 20:38
问题解决了就把类型改成提问结束1
作者: che201311    时间: 2013-11-30 21:02
hashcode有可能一样在同一个卡块中




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