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

18 篇文章 0 订阅

关注公众号“码农帮派”,查看更多系列技术文章:

   

 

  我们知道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值返回。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值