<九>重写equals方法必须重写hashcode方法

java Guide里说到了为什么要重写hashcode的原因:

为什么重写equals时必须重写hashcode方法?

如果两个对象相等,则hashcode一定也是相同的。两个对象相等,对两个对象分别调用equals方法都返回true。但是,两个对象有相同的hashcode值,它们也不一定是相等的。因此,equals方法被覆盖过,则hashcode方法也必须被覆盖。

 一定要重写hashcode的主要原因是要保障equals方法的特性,即equals返回结果必须与其hashcode比较结果保持一致

为什么要这样保障呢?

1、了解hashcode是干啥的

hashcode()的默认行为是对上的对象产生独特值。如果没有重写hashcode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

2、了解一个过程

确定和保障对象的唯一性,我们在使用set和map的时候有下面这样一个先hashcode确定唯一性的过程。

      当你把对象加入HashSet时,HashSet会先计算对象的hashcode值 来判断对象加入的位置,同时也会与其他已经加入的对象的hashcode值作比较,HashSet如果没有相符的hashcode,会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。

 从上面两点我们来分析如果不重写hashcode会有什么后果。

我们这样去利用一个map看下他的打印结果:

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}
/**
     * @see Person
     * @param args
     */
    public static void main(String[] args)
    {
        HashMap<Person, Integer> map = new HashMap<Person, Integer>();

        Person p = new Person("jack",22,"男");
        Person p1 = new Person("jack",22,"男");

        System.out.println("p的hashCode:"+p.hashCode());
        System.out.println("p1的hashCode:"+p1.hashCode());
        System.out.println(p.equals(p1));
        System.out.println(p == p1);

        map.put(p,888);
        map.put(p1,888);
        map.forEach((key,val)->{
            System.out.println(key);
            System.out.println(val);
        });
    }

p的hashCode:356573597
p1的hashCode:1735600054
false
false
com.blueskyli.练习.Person@677327b6
888
com.blueskyli.练习.Person@1540e19d
888

可以看到两个对象作为key值的时候,比较的hashcode实际上是堆上的内存地址。而如果我们想用name来做唯一性,需要先重写其equals

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override public boolean equals(Object obj)
    {
        if(obj instanceof Person){
            Person person = (Person)obj;
            return name.equals(person.name);
        }
        return super.equals(obj);
    }
}

继续执行上面例子的打印,其结果如下:
其比较结果为:
p的hashCode:356573597
p1的hashCode:1735600054
true
false
com.blueskyli.练习.Person@677327b6
888
com.blueskyli.练习.Person@1540e19d
888

我们发现虽然我们已经重写了equals,但是其在hashmap中仍然设置进去了两个name值相同的对象。

如果我们想在map或者set中也根据name做其唯一性的话,必须重写hashcode。

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override public boolean equals(Object obj)
    {
        if(obj instanceof Person){
            Person person = (Person)obj;
            return name.equals(person.name);
        }
        return super.equals(obj);
    }

    @Override public int hashCode()
    {
        return name.hashCode();
    }
}

p的hashCode:3254239
p1的hashCode:3254239
true
false
com.blueskyli.练习.Person@31a7df
888

总结:

  1. 两个对象,用==比较比较的是地址,需要采用equals方法(可根据需求重写)比较
  2. 重写equals()方法就是重写hashcode()方法。
  3. 一般相等的对象都规定有相同的hashcode
  4. String 类重写了equals和hashcode方法,比较的是值。
  5. 重写hashcode方法为了将数据存入Hashset/HashMap/Hashtable类时进行比较。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值