前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么重写对象equals方法要重写hashcode方法的真正原因!

为什么重写对象equals方法要重写hashcode方法的真正原因!

作者头像
名字是乱打的
发布2021-12-24 09:25:01
9241
发布2021-12-24 09:25:01
举报
文章被收录于专栏:软件工程

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

3)为什么重写 equals 时必须重写 hashCode 方法? 如果两个对象相等,则 hashcode 一定也是相同的。两个对象相等,对两个对象分别调用 equals 方法都返回 true。但是,两个对象有相同的 hashcode 值,它们也不一定是相等的 。因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖。 hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

但是我没太理解,两个对象有相同的code他们不一定是相等的又咋样,为什么就要重写hashcode?

后面自己看了别的博文,理解了下,我觉得一定要重写hashcode的主要原因是要保障equals方法的特性,即equals返回结果必须与其hashcode比较结果必须保持一致.

为什么要这样保障呢?
1.了解hashcode是干啥的

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

2.了解一个过程
  • 1.确定和保障对象的唯一性,我们在使用set和map的时候有下面这样一个先hashcode确定其唯一性的过程

当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals() 方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的 Java 启蒙书《Head First Java》第二版)。,为什么呢 ?这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

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

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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

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

代码语言:javascript
复制
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();
    }
}

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

代码语言:javascript
复制
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(可以参考源码有助于理解)类时进- 行比较
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/6/7 上午,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么要这样保障呢?
    • 1.了解hashcode是干啥的
      • 2.了解一个过程
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档