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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 啷个里个郞 于 2012-5-11 23:29 编辑

请详细解答。谢谢

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

3 个回复

倒序浏览
当我们重写了对象的equals方法,一般情况下(这里我指这些对象不需要放到Set或Map中仅仅是比较需要,或者虽然放到Set或Map中,但是get和set时用的是同一对象)是没有问题的,但是,有些情况下就不同了;举个例子

public class Person(){

private int id;

private String name;

//define getter and setter here, omited



public void equals(Object obj){

if (!(obj instanceof Person))
            return false;
return super.equals(obj) && ((Member) obj).getId() == this.getId();

}

}

上述class中没有覆盖hashCode方法,因此这个时候用的是Object.hashCode()的返回值;我们来测试一下

public class TestHashCode extends TestCase {
   
        public void testMap() {
        Person p1 = new Person(1,"aaa"),p2 = new Person(1,"bbb");
        Map map = new HashMap();
        map.put(p1,p1);
        Member value = (Person)map.get(p2);
        System.out.println(value.getName());
    }

}

请注意,这两个对象是相等的,可以从equals()的定义看出来;运行TestHashCode ,结果是NullPointerException;

现在添加hashCode()到Person中

public int hashCode() {
        
        return this.getId() * 37 ;
    }

重运行TestHashCode ;huh,我们想要的结果出现了,“aaa”

为什么,老早的时候我就问过自己,只怪自己不求甚解;其实很简单

Map.put(key,value)时根据key.hashCode生成一个内部hash值,根据这个hash值将对象存放在一个table中

Map.get(key)会比较key.hashCode和equals方法,当且仅当这两者相等时,才能正确定位到table;

回到先前的问题,为什么添加person.hashCode()前,得不到person对象;因为java中默认的hashCode是根据对象的地址计算得到的,虽然p1.equals(p2)=true,但是p1,p1有不同的内存地址,所以有不同的hashCode;所以通过p2是不能得到value的,这个时候value==null;添加hashCode()后,两个对象有相同hashCode,所以能得到

java中Set是通过Map实现的,所以Map和Set的所有实现类都要注意这一点

HashMap是通过链地址法解决hash collision的,并且新对象都是添加到表头的

点评

你懂的··http://bbs.itheima.com/thread-14253-1-1.html  发表于 2012-5-11 23:09
谢谢  发表于 2012-5-11 22:31
回复 使用道具 举报
这种做法一般是为了增强自定义类的扩展性,尤其是当该类的对象要存入HashSet集合时,覆写这两个方法尤为重要。覆写equals方法之后,可以实现对象的自定义比较,如果不覆写此方法,默认调用Object的equals方法,等同于比较地址值。如果一个类不覆写Object中的hashCode方法,而直接调用该方法,得到的哈希值是由系统计算出的,返回值和对象属性之间没有直接联系。覆写hashCode方法,可以根据对象属性的不同,返回相应的哈希值。
具体到HashSet集合中对这两个方法的调用步骤,如下:
1)当向集合中存入一个元素时,会调用该元素的hashCode方法,得到该对象哈希值,如果集合中已有元素的哈希值和该元素的哈希值不重复,该元素被存入集合。
2)如果要存入元素的哈希值和已有元素的哈希值相同,会进一步调用equals方法,比较这两个元素是否相同,如果不同,该元素依然会被存入集合,如果相同,则认为这两个元素相同,由于集HashSet集合中不能存入相同元素,所以存储动作不会成功。
需要说明的是:覆写这两个方法并非必须。如果只是编写一个用于测试的简单类,完全没有必要一定覆写这两个方法。只是一般开发中考虑到程序的扩展性,或者该类对象有可能被存储到HashSet中,覆写这两个方法可以为以后程序的升级提供方便。当然,一个好的类,一般会覆写Object中的equals方法、hashCode方法、toString方法等。

点评

谢谢  发表于 2012-5-11 22:30

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
黄坚声 发表于 2012-5-11 17:46
当我们重写了对象的equals方法,一般情况下(这里我指这些对象不需要放到Set或Map中仅仅是比较需要,或者虽 ...

你懂的
http://bbs.itheima.com/thread-14253-1-1.html
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马