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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 陈雪琪 中级黑马   /  2013-5-15 19:00  /  1737 人查看  /  14 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 陈雪琪 于 2013-5-15 21:57 编辑
  1. class HashSetDemo
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Demo d1=new Demo();
  6.                 Demo d2=new Demo();
  7.                 sop(d1);
  8.                 sop(d2);
  9.                 sop(d1.equals(d2));
  10.         }
  11.         public static void sop(Object obj){
  12.                 System.out.println(obj);
  13.         }
  14. }
  15. class Demo
  16. {
  17.         public int hashCode(){
  18.                 return 60;
  19.         }
  20. }
复制代码
输出结果:
Demo@3c
Demo@3c
false
毕老师在视频中将hashCode()方法复写后,返回60,所以创建的两个Demo对象打印后输出的都是Demo@3c
它们的哈希值是一样的,老毕说这个时候就会调用equals方法比较两个对象了。
我在main方法中输出比较结果为false。我也很明白new的的确是两个不同的对象,不明白的是equals方法
比较对象的时候比较的是地址值对吧?它们的地址值不都是Demo@3c么?难道这两个对象都存在在这个地址上?
那似乎也不太对。那么equals方法此时到底是怎么比较出为false的呢?

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

14 个回复

倒序浏览
同求。楼主好认真的思考了。我刚看过这个,我该反思了。。。

点评

也没有啦 就是突然闪过的莫名其妙的念头。  发表于 2013-5-15 20:53
回复 使用道具 举报
楼主,如果要用hashSet存储自定义对象的话,一般是要重写hashCode()和equals()这两个方法的。
当两个对象的哈希值相同时,就像楼主的都为Demo@3c时,才会调用equals()方法,但是equals()函数是要楼主自己在Demo类中重写的,
重写时以自己的需求来判断两个对象是否相等。
楼主重写了hashCode()函数,以至于返回的哈希值相同了,但实际上两个对象的地址值还是不同的,所以对象调用自己原来的equals方法判断时返回的还是false,
不知道楼主明白了没有?

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

回复 使用道具 举报
class HashSetDemo
{
        public static void main(String[] args)
        {
                Demo d1 = new Demo();
                Demo d2 = new Demo();
                                Demo d3 = new Demo();


                sop(d1);
                sop(d2);

                                //调用equasla方法比较
                sop(d1.equals(d2));
                                sop(d2.equals(d3));
                                sop(d3.equals(d1));
                                /*
                             d1.equals(d2);d1这个引用指向的是一个自建Demo对象,该对象
                                 继承自Object类。由于没有覆盖Object类,d1会调用Objcet类的
                                 equals方法:(该方法源码)
                                      public boolean equals(Object obj) {
                                        return (this == obj);
                                  }

                                 这里要问两个问题:java中 对象的hash code与对象应用的内存地址都是干什么的?
                                 hashcode是对象的散列码,主要用在哈希表中,优化检索速度!
                 对象引用通俗来说就是对象的名字,存储在栈上,其内容是真正存储对象值的堆的首地址。

                                 在这个问题上,老毕并没有说清楚。
                                 Demo d1 = new Demo();
                 Demo d2 = new Demo();
                                 Demo d3 = new Demo(); 很明显的,这里新建了三个对象,划分了三块内存,d1、d2、d3这
                                 三个引用对应不同的地址值。当调用没有覆盖的equals方法时,自然会去比较它们的地址值,
                                 而不是你改写的hashCode值。这就是症结所在。
                                */
        }
        public static void sop(Object obj){
                System.out.println(obj);
        }
}
class Demo  //新建一个普通类:这个类继承自Object。
{
            //重写hashcode方法
        public int hashCode(){
                return 60;
        }
}

class Test
{
}
/*
---------- 运行java程序 ----------
Test@1fb8ee3
Demo@3c
Demo@3c
false
false
false

输出完成 (耗时 0 秒) - 正常终止
*/

评分

参与人数 1技术分 +1 收起 理由
滔哥 + 1

查看全部评分

回复 使用道具 举报
徐启坤 发表于 2013-5-15 20:32
楼主,如果要用hashSet存储自定义对象的话,一般是要重写hashCode()和equals()这两个方法的。
当两个对象的 ...

还是没懂吖   老毕视频中是说3c是地址值,为什么实际的对象地址值还是不同呢?equals方法不就是判断地址值是否相同的么?
回复 使用道具 举报
不好意思 没注意排版 输出结果也是之前测试的
回复 使用道具 举报
class HashSetDemo
{
        public static void main(String[] args)
        {
                Demo d1 = new Demo();
                Demo d2 = new Demo();
                Demo d3 = new Demo();


                sop(d1);
                sop(d2);

                //调用equasla方法比较
                sop(d1.equals(d2));
                sop(d2.equals(d3));
                sop(d3.equals(d1));
                                /*
                               d1.equals(d2);d1这个引用指向的是一个自建Demo对象,该对象
                                 继承自Object类。由于没有覆盖Object类,d1会调用Objcet类的
                                 equals方法:(该方法源码)
                                      public boolean equals(Object obj) {
                                        return (this == obj);
                                  }

                                 这里要问两个问题:java中 对象的hash code与对象应用的内存地址都是干什么的?
                                 hashcode是对象的散列码,主要用在哈希表中,优化检索速度!
                                 对象引用通俗来说就是对象的名字,存储在栈上,其内容是真正存储对象值的堆的首地址。

                                 在这个问题上,老毕并没有说清楚。
                                 Demo d1 = new Demo();
                                 Demo d2 = new Demo();
                                 Demo d3 = new Demo(); 很明显的,这里新建了三个对象,划分了三块内存,d1、d2、d3这
                                 三个引用对应不同的地址值。当调用没有覆盖的equals方法时,自然会去比较它们的地址值,
                                 而不是你改写的hashCode值。这就是症结所在。
                                */
        }
        public static void sop(Object obj){
                System.out.println(obj);
        }
}
class Demo  //新建一个普通类:这个类继承自Object。
{
            //重写hashcode方法
        public int hashCode(){
                return 60;
        }
}


/*
---------- 运行java程序 ----------
Demo@3c
Demo@3c
false
false
false

输出完成 (耗时 0 秒) - 正常终止
*/



回复 使用道具 举报
陈雪琪 发表于 2013-5-15 20:52
还是没懂吖   老毕视频中是说3c是地址值,为什么实际的对象地址值还是不同呢?equals方法不就是判断地址值 ...

你要查看下 equals 方法 和 hashCode 方法到底是如何实现的。说白了 equals方法只是给定了一种比较的方式,当你新建一个普通类,该类会自动继承Object类,当你调用equals方法时,这时你就要去看调用对象是如何规定equals方法的。
回复 使用道具 举报
陈雪琪 发表于 2013-5-15 20:52
还是没懂吖   老毕视频中是说3c是地址值,为什么实际的对象地址值还是不同呢?equals方法不就是判断地址值 ...

楼主你可能明白了hashCode()函数返回的是对象的地址值,但这是未被你重写之前的功能,但是hashCode()函数现在已经被你重写了,所以现在它返回的不再是地址值,而只是你让它返回的一个数而已,明白了没
回复 使用道具 举报
陈雪琪 发表于 2013-5-15 20:52
还是没懂吖   老毕视频中是说3c是地址值,为什么实际的对象地址值还是不同呢?equals方法不就是判断地址值 ...

老毕说3C是地址值,实际上并不不对。Demo d1 = new Demo(); 这句运行时,开辟了两块空间:堆内存(存储对象),栈内存(存储引用d1),而d1 到底存储的是什么了? 它是 对象所在内存的首地址。
回复 使用道具 举报
徐启坤 发表于 2013-5-15 21:02
楼主你可能明白了hashCode()函数返回的是对象的地址值,但这是未被你重写之前的功能,但是hashCode()函数 ...

那这么说的话  感觉老毕说的有点不对了呢,那它就并不能算是地址值咯?
不过也是  计算机给你的内存地址也不是说变就变得  都安排好了  
那么equals比较的就是内存中的地址值咯?
回复 使用道具 举报
不胖的胖子 发表于 2013-5-15 20:56
class HashSetDemo
{
        public static void main(String[] args)

那么这么说的话   其实地址值并没有被改变   改变的只是hashcode值,而这个值已经不是对象的地址值了   那么这样的话是不是就没有办法打印出对象真正的地址值了呢?
回复 使用道具 举报
陈雪琪 发表于 2013-5-15 21:20
那么这么说的话   其实地址值并没有被改变   改变的只是hashcode值,而这个值已经不是对象的地址值了    ...

说对了。其实我在上面的代码中就写到了。只是你没看到重点而已!!
hashCode其实是在HashSet中用到的多,因为在HashSet中低层数据就是哈希表,当把对象(其实是引用)存储到其中,可以方便的检索。当你存储时,引用指向的值变了,你才能判断。其实我们要清楚的知道在运行阶段,
引用指向了谁,比较才有意义。
回复 使用道具 举报
public class Test
{

    //覆盖equals方法
        public boolean equals(Object obj){
                return true;
        }
        //覆盖hahsCode方法
        public int hashCode(){
                return 60;
        }
        public static void main(String args[]){
              Test t1 = new Test();
                          Test t2 = new Test();

                          System.out.println(t1);
                          System.out.println(t2);

                          System.out.println(t1 == t2);
                          System.out.println(t1.equals(t2));
        }
}
/*
---------- 运行java程序 ----------
Test@3c
Test@3c
false
true

输出完成 (耗时 0 秒) - 正常终止

写这个例子是为了说明,hashCode 和实际对象引用的地址值是不同的东西。
你可以看到,引用一直指向的是我们建立的对象。没有存储到什么容器中。
在运行期间没有改变。
  
你还要注意两个问题:当我们写 t1.equals(t2) 这个equals 方法到哪查看?
还有 == 与 equals的区别。
这些你都要明白。才能对视频中说的有清楚的认识
*/

回复 使用道具 举报
不胖的胖子 发表于 2013-5-15 21:39
public class Test
{

谢谢指正   说的很清楚!  :loveliness:
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马