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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 聂斌 中级黑马   /  2013-3-26 18:50  /  2547 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 聂斌 于 2013-3-26 19:51 编辑

public class ReflectPoint {
        private int x;
        public int y;
        
        public String str1 = "ball";
        public String str2 = "basketball";        
        public String str3 = "itcast";

        @Override
        public boolean equals(Object obj) {
                if (this == obj)
                        return true;
                if (obj == null)
                        return false;
                if (getClass() != obj.getClass())
                        return false;
                ReflectPoint other = (ReflectPoint) obj;
                if (x != other.x)
                        return false;
                if (y != other.y)
                        return false;
                return true;
        }

        public ReflectPoint(int x, int y) {
               
                this.x = x;
                this.y = y;
        }
        
        
}


                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());

输出:3

老师的代码中是没有重写hashcode()方法的,j结果是3,,我的理解是最后一个pt1l是没有放进集合中的,,,,但是我看老师说的讲解是这样的:

视频26,,时间第12:00分钟开始,,,

下面是老师的话语:

虽然pt1和pt3使用equsal()方法(重写equals方法)比较是相等了,但是你算出来的hashcode值是按照内存地址值算的,他们2个的内存地址值不一样,这2个本来该认为是相同的对象,分别被存放到了不同的区域当中(pt1__1区域,,pt3__2),.....当我要去找这个对象pt3时,我在我这个2区域里面找,不在1区域里找,虽然那个1区域确实有个和我相同的对象pt1,但是我没有去1区域里找,,所以pt3就没有放进去,,

问题:
老师说的话我始终无法理解,,为什么老师会说pt3没有放进去呢,,,当我写代码验证时pt3放进集合中了,,是最后一个pt1没有放进去,,,,老师说的话大家怎么理解,,我一直想不通,,,郁闷了好久,,

我明白pt1和pt3使用equsal()方法 他们是相等的,那么Pt3就不会放进集合中,,,但是我通过下面代码2验证时发现pt3放进去了是最后一个pt1没有放进去,,


代码2:

        Collection collections = new HashSet();
               
                ReflectPoint pt1 = new ReflectPoint(3,3);
                ReflectPoint pt2 = new ReflectPoint(5,5);
                ReflectPoint pt3 = new ReflectPoint(3,3);        
//                System.out.println(pt1.equals(pt3));
//                System.out.println(pt1.equals(pt1));
                System.out.println(pt1);
                System.out.println(pt2);
                System.out.println(pt3);
                collections.add(pt1);
                collections.add(pt2);
                collections.add(pt3);
                collections.add(pt1);
                System.out.println( pt1== pt1);
                System.out.println(collections);
                System.out.println( pt1.equals(pt1));
                System.out.println(collections.size());


输出:

june26.ReflectPoint@c17164
june26.ReflectPoint@1fb8ee3
june26.ReflectPoint@61de33
true
[june26.ReflectPoint@1fb8ee3, june26.ReflectPoint@c17164, june26.ReflectPoint@61de33]
true
3



在这里想听听大家对老师的原话理解,,,, 就是视频26,,时间第12:00分钟开始到14;00分钟,,

点评

如果问题为解决,请继续追问,如果解决了,请将分类改为已解决,谢谢  发表于 2013-3-26 19:44

8 个回复

倒序浏览
本人在此恭候大家的高见,,,,急急急,,,,
回复 使用道具 举报
老师说pt3没放进去,是说没放进去1区域,并没说没放进别的区域。如果你用自己的算法算的哈希值,可能两个相同的对象,哈希值不同,就不会被覆盖的。
回复 使用道具 举报
黄玉昆 发表于 2013-3-26 19:06
老师说pt3没放进去,是说没放进去1区域,并没说没放进别的区域。如果你用自己的算法算的哈希值,可能两个相 ...


老师说pt3没放进去,是说没放进去1区域,,这个就懂了,,如果是放进去1区域那就对头,,呵呵谢谢哈
回复 使用道具 举报
虽然pt1和pt3使用equsal()方法(重写equals方法)比较是相等了,但是你算出来的hashcode值是按照内存地址值算的,他们2个的内存地址值不一样,这2个本来该认为是相同的对象,分别被存放到了不同的区域当中(pt1__1区域,,pt3__2),.....当我要去找这个对象pt3时,我在我这个2区域里面找,不在1区域里找,虽然那个1区域确实有个和我相同的对象pt1,但是我没有去1区域里找,,所以pt3就没有放进去,,

回答:其实你理解的是正确的。只是老师是想告诉你这个pt3一但放入集合用了,你就再也取不出它了,这样就会内存溢出。
因为pt1和pt3本来是两个相同的对象(这是指你在定义对象的时候是这么想的,只要字节码相同,x,y值相等就是同一个对象了。)。
可是pt1,和pt3在这里不是一个对象的原因是因为它们的hash值不同。
一但hash值不同,那么当被存入hash表的时候,首先去计算对象的hash值,来决定对象的存放位置。
可以pt1和pt3的hash值都不相等。所以会被存放到不同的地方
但是当我们每次去取pt3的时候,而是在pt1存放的地方去找,这样肯定永远找不到pt3了,
用户并不知道,还不停地向集合中添加pt3一样的对象,而每次找却只在集合中pt1的位置找。
这样内存中的pt3这种地址值不同的对象越来越多,最后就会出现内存溢出了。

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
itserious 发表于 2013-3-26 19:25
虽然pt1和pt3使用equsal()方法(重写equals方法)比较是相等了,但是你算出来的hashcode值是按照内存地址值算 ...

但是当我们每次去取pt3的时候,而是在pt1存放的地方去找,这样肯定永远找不到pt3了,这句话我说说我的理解;

当我存入pt3时我会去pt1存放的地方之外的区域去找有没有和pt3相同的对象,如果其他区域里面有相同的Pt3,,,,那么pt3就不存放进去了,,


不知道我的理解是否恰当,,上面的玉昆同学说的Pt3没有放到1区域中是合理的,,那样的话一切问题就解决了,,我之前一直想不通的是我理解错了老师的原话,,我理解的是pt3没有放到集合中,,就是这个把我糊涂了
回复 使用道具 举报
pt3是放进去了的,只是放在其它地方去了的,因为什么的hash值不同,hashSet集合会直接认为它们是两个不同的对象了。

你想要pt3 和pt1 相同,那么你必须重写hashcode方法。因为你不重写它就会用Object的hashcode方法,直接去计算地址值了。

你要向底层是hash表结构的集合添加元素,你最好重写hashcode方法,用你的对象的自身属性来计算hash值。这样就可以实现
自定义的比较方式。
回复 使用道具 举报
1hashset在添加元素师首先计算hashcode每个hashcode对应一个区域
2然后拿要添加的元素在该区域和原有的元素使用equals方法比较,如果有相同的元素就不添加返回false,如果没有相同的元素,就添加在该区域。
在老师的例子中pt1和pt3的hashcode不同(因为是根据地址计算的,两个对象不在同一个地址),所以映射到不同的区域,pt3不可能和pt1比较,所以就加入了hashset。再一次加入pt1显然是不行的。

其实一个hashcode的值的域可以对应一个指针数组,每个指针数组的元素作为一个链表头。这样就可以实现一个哈希表。
回复 使用道具 举报
聂斌 中级黑马 2013-3-26 21:54:54
9#
itserious 发表于 2013-3-26 19:56
pt3是放进去了的,只是放在其它地方去了的,因为什么的hash值不同,hashSet集合会直接认为它们是两个不同的 ...

hashset集合的比较方式我是很清楚的,之前老毕讲的就很好,,,我只是理解错了老师的原话,认为ipt3没有放到集合中,,,因为老师是那样说的,,只是他没有讲的很明白说pt3没有放到1区域中,,,玉昆同学说的Pt3没有放到1区域中我就把一切都想通了,,,,,我之前纠结的地方是老师说pt3没有放到集合中,,,所以想了很久,,,,,
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马