A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 朱亚安 中级黑马   /  2012-3-18 16:13  /  2947 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

Collection c=new HashSet();
Point p1=new Point(3,3);
Point p2=new Point(3,4);
Point p3=new Point(3,5);
c.add(p1);
c.add(p2);
c.add(p3);

p1.y=6;
c.remove(p1);
System.out.println(c.size());
打印的是3,视频上老师说,是hashcode码变了但是为什么变了就删除不了呢。
HashSet里面:boolean remove(Object obj)是方法原型,是说在该set里面有和p1,equals()的对象就移除不是吗。那为什么说hashcode变了就删除不了了呢?

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

9 个回复

倒序浏览
移除一个对象时先拿这个元素的hashcode值在hashset集合里找具有相同hashcode值的对象,如果没找到具有相同hashcode值的对象,他认为集合里没这个对象,也就谈不上删除了
如果有再用equals比较两个对象是否相等,如果equals返回true,就把这个对象从集合里删除,

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
equals()默认的比较是hashcode值 hashcode值是从内存地址换上出来的
HashSet存储是对象是要看对象的hashCode值的 HashSet把空间按hashCode的范围分成若干个区域。
当要查找对象时先看对象的hashCode()在哪个区域内在去那个区域找 这样的话就提高了查找效率。
存储的时候也一样依据对象的hashCode()把它存进特定的区域。
Point p1=new Point(3,3);
c.add(p1);
执行以后就把p1 假设按p1 的hashCode()值存进了甲区域。
p1.y=6;后p1的hashCode()值改变了。假设改变后的cashCode()值符合HashSet的乙区域。
c.remove(p1);后 hashSet会去存储区域的乙区域找这个对象 因为乙区域里没有这个对象所以就找不到了自然remove()不了
c.size()的大小没变化。

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
       HashSet依赖的是元素的hashCode()和equals()方法,:
         1)首先判断元素哈希值
         2)哈希值不同,不需要再判断元素的equals()方法,返回false
             3)哈希值相同,判断equals()方法。如果equals()方法相同返回true,视为同一个元素;不同返回false,视为不同的元素,会存储在同一个哈希值上
         4)所以我们要重写hashCode()和equals()方法,hashCode()用来判断集合元素对象,而equals()用来判断元素对象的属性值是否相同

1.两个对象的值相同,它的hashCode值是肯定相同的
2.两个对象的值不同时,它的hashCode值不能肯定就相同。但是产生不同的hashCode值可以提高哈希表的性能
3.你可以打印p1再次赋值之前的hashCode值和赋值后的hashCode值,如果想删除的话,可以重写remove方法

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
HashSet内部使用哈希算法去重复的, 当存储对象的时候,先调用对象的HashCode()方法计算一个哈希值, 然后在集合中查找是否有哈希值相同的对象, 如果没有见哈希值相同的对象就直接存入, 如果有相同的就调用equals()方法比较, 比较结构为true就不存, 你叫结果为false则直接存入;
但是, 向HashSet中存储自定义类的对象时, 如果没又重写equals()方法, 那么将会调用Object类的HashCode()方法, 得到当前对象的地址值, 地址簿同也不能去重复;
如果想要相同属性的对象去重复, 那么属性相同的对象必须要返回相同的哈希值, 在HashSet中存储自定义对象, 如果希望去掉重复的元素, 就要重写hashCode()方法和equals()方法;
回复 使用道具 举报
public class TestArray {
public static void main(String[] args) {
        Collection c=new HashSet();
        Point p1=new Point(3,3);
        Point p2=new Point(3,4);
        Point p3=new Point(3,5);
        c.add(p1);
        c.add(p2);
        c.add(p3);

        p1.y=6;
        c.remove(p1);
        System.out.println(c.size());
}


}
class Point
{
        public Point(int x, int y) {
                super();
                this.x = x;
                this.y = y;
        }
         int x;
         int y;
        public int getX() {
                return x;
        }
        public void setX(int x) {
                this.x = x;
        }
        public int getY() {
                return y;
        }
        public void setY(int y) {
                this.y = y;
        }
}
我的测试是2
回复 使用道具 举报
魏群 发表于 2012-3-18 17:05
equals()默认的比较是hashcode值 hashcode值是从内存地址换上出来的
HashSet存储是对象是要看对象的hashCod ...

      你的意思是不是说,其实在这个成员变量的修改中只是hashCode值变了而这个对象本身的物理地址并没有变,还在你所说的“甲区域内”,hashSet删除的时候会根据已经改变了的hashCode值去“乙区域”找,可惜现在的hashCode已经不再反应物理地址是不是,所以就没有删除掉呀?
     好像还真是这么个意思,我可是在这里纠结了一个下午了......谢谢了
回复 使用道具 举报
liumeng 发表于 2012-3-18 20:03
public class TestArray {
public static void main(String[] args) {
        Collection c=new HashSet();

关键就看remove这个方法具体是怎么操作的 第一根据hash值判断的 而各个元素hash值一般是根据元素本身的成员属性乘以某个整数相加而得来的 p1.y=6;这样就改变了hash值 然后这样remove就失败了
既然如此 集合长度应该是3啊
回复 使用道具 举报
王思兰 黑马帝 2012-3-19 14:28:07
9#
y值改变了,就表示哈希值变了,哈希值一变,你这代码中p1的存储的位置就不在原来划分的区域里了,p1不存在那里了,所以就删不了
回复 使用道具 举报
OMG 中级黑马 2012-3-19 14:44:59
10#
形象地说是内存泄漏,确切地说是对象的索引(哈希码)与对象失去联系,导致虚拟机无法通过哈希码读取并删除对象!
所以,凡是参与哈希值计算的变量值尽量避免修改,以免内存泄漏!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马