为什么重写了equals()之后还要重写hashCode()

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tianmaxingkong_/article/details/52127370

      我们知道equals()和hashCode()是java Object中两个基本方法,有时候由于业务的需求,需要我们重写equals()方法,比如对于Person类中,业务的需要让我们当Person对象的cardID一致的时候,就认为两个对象equals,此时就需要在Person类中重写equals()方法,如下:

public class Person
{

    public String name;
    public int age;
    public String cardID;

    .....// 省略

    @Override
    public boolean equals(Object o)
    {
        if (o instanceof Person)
        {
            Person p = (Person) o;
            return this.cardID.equals(p.cardID);
        } else
        {
            return false;
        }
    }

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

    ......// 省略


}

      阅读HashMap的源码,我们可以看到,HashMap中实现了一个Entry[]数组,数组的每个item是一个单项链表的结构,当我们put(key, value)的时候,HashMap首先会newItem.key.hashCode()作为该newItem在Entry[]中存储的下标,要是对应的下标的位置上没有任何item,则直接存储上去,要是已经有oldItem存储在了上面,那就会判断oldItem.key.equals(newItem.key),那么要是我们把上面的Person作为key进行存储的时候,重写了equals()方法,但没重写hashCode()方法,当我们去put()的时候,首先会通过hashCode() 计算下标,由于没有重写hashCode(),那么实质是完整的Object的hashCode(),会受到Object多个属性的影响,本来equals的两个Person对象,反而得到了两个不同的下标。


      同样的,HashMap在get(key)的过程中,也是首先调用hashCode()计算item的下标,然后在对应下标的地方找,要是为null,就返回null,要是 != null,会去调用equals()方法,比较key是否一致,只有当key一致的时候,才会返回value,要是我们没有重写hashCode()方法,本来有的item,反而会找不到,返回null结果。


      所以,要是你重写了equals()方法,而你的对象可能会放入到散列(HashMap,HashTable或HashSet等)中,那么还必须重写hashCode(), 如果你的对象有可能放到有序队列(实现了Comparable)中,那么还需要重写compareTo()的方法。


public class Person implements Comparable
{

    public String name;
    public int age;
    public String cardID;

    ..... // 省略
    
    @Override
    public boolean equals(Object o)
    {
        if (o instanceof Person)
        {
            Person p = (Person) o;
            return this.cardID.equals(p.cardID);
        } else
        {
            return false;
        }
    }

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

    @Override
    public int compareTo(Object another)
    {
        Person p = (Person) another;
        return p.cardID.compareTo(this.cardID);
    }

    ..... // 省略

}



[补充]

其实对于大多数情况下,我们都需要重写类的equals()方法:

public class Person
{

    public String name;
    public int age;
    public String cardID;

}

对两个Person对象的equals()的结果:

public static void main(String[] args)
{
    Person person = new Person();
    person.name = "MXD";
    person.age = 4;
    person.cardID = "110";

    Person person0 = new Person();
    person0.name = "MXD";
    person0.age = 4;
    person0.cardID = "110";

    System.out.println(person.equals(person0));
    System.out.println("person的hashCode:" + person.hashCode());
    System.out.println("person0的hashCode:" + person0.hashCode());
}

理论上应该返回true,但是:


这是因为,equals默认的比较的是person在内存中存储的位置,而不是内容是否相同,当我们对Person的equals()进行重写之后:

(下面是我们对Person类的equals方法以及hashCode方法进行重写之后的类):

public class Person
{

    public String name;
    public int age;
    public String cardID;

    @Override
    public boolean equals(Object obj)
    {
        if (obj instanceof Person)
        {
            Person p = (Person) obj;
            return this.cardID.equals(p.cardID) && this.name.equals(p.name) && this.age == p.age;
        }else{
            return false;
        }
    }

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

}

针对之前相同的main()函数中的比较,得到的结果为:



我们发现,两个内容一致的Person对象的equals返回了true,而且hashCode也相同了。


[值得注意的是]

      上面对hashCode()的重写中,只涉及到了cardID一项,更合理的是,所有属性的结合,比如各个属性的hashCode()再求异或,作为对象的hashCode值返回。

展开阅读全文

没有更多推荐了,返回首页