覆盖equals方法时需要注意什么以及为什么同时也要覆盖hashcode方法?

覆盖equals方法时需要注意什么以及为什么同时也要覆盖hashcode方法?

首先,贴上一个重写equals方法和hashcode方法的对象的实例代码:

public class Demo1 {

    private Integer id;
    private String name;
    private String orgNames;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getOrgNames() {
        return orgNames;
    }

    public void setOrgNames(String orgNames) {
        this.orgNames = orgNames;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Demo1 demo1 = (Demo1) o;
        return
                Objects.equals(id, demo1.id) &&
                Objects.equals(name, demo1.name) &&
                Objects.equals(orgNames, demo1.orgNames);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, orgNames);
    }
}

众所周知,Java的Object类是实现了equals方法的,实现规则是:类的每个对象都只与它自身相等。

看一下下面的例子,输出结果是什么(该类没有覆写equals方法):

 public void get(){
        DemoEH demoEH = new DemoEH();
        demoEH.setName("name");
        demoEH.setId("id");
        DemoEH demoEH1 = new DemoEH();
        demoEH1.setName("name");
        demoEH1.setId("id");
        boolean equals = demoEH.equals(demoEH1);
        System.out.println(equals);
    }
    
---------------------------------result----------------------------------------
false

很明显,控制台输出结果为false。

在说明什么情况下需要重写equals方法之前,我们先说明一下,什么情况不需要重写:

  1. 类的每个实例本质上都是唯一的。
  2. 类没有必要提供逻辑相等的测试功能。
  3. 超类已经覆盖了equals,超类的行为对于这个类也是合适的。
  4. 类是私有的,或者是包级私有的,可以确定他的equals方法永远不会被调用。

就像上边我们写的这个例子,两个对象的值是一样的(我们理解为逻辑相等),但是调用Object的equals方法我们发现,返回的是false,这种情况下我们如果想让其返回true的话,就需要重写equals方法。

那么我们在什么时候应该覆盖equals方法呢?

如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals。

在覆盖equals方法时,必须要遵守他的通用约定,即:

  1. 自反性
  2. 对称性
  3. 传递性
  4. 一致性
  5. 非空性

切记,一旦违反了equals约定,当其他对象面对你的对象时,你完全不知道这些对象的行为会怎么样。

那么在覆盖equals时,为什么总要覆盖hashcode方法呢?

首先我们需要了解一下hashcode的通用规范(这是你必须要知道的):

  1. 在应用的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对同一个对象的多次调用,hashcode方法都必须始终返回同一个值。在一个应用程序与另一个应用程序的执行过程中,执行hashcode方法所返回的的值可以不一致。
  2. 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象的hashcode方法必须产生同样的整数结果。
  3. 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中的hashcode方法,则不一定要求hashcode方法必须产生不同的结果。

如果我们在覆盖了equals方法时没有覆盖hashcode的话,就违反了相等的对象必须具有相等的散列码(hashcode)这一约定。

那么散列码在我们的程序中有什么作用呢?

举个例子,HashMap中有一项优化,可以将与每个项相关联的散列码缓存起来,如果散列码不匹配,也就不再去检验对象的等同性。这句话是什么意思呢,就是我们定义了一个map,我们在获取其中某一个key的值时,hashmap会先去寻找这个key的对象的hashcode,如果没有找到相同的hashcode值,那么就不会再去找这个对象的key了,就会直接返回空。

ps:不理解的话可以先了解一下hashMap

所以对于我们的程序来讲,重写equals之后重写hashcode是必要的。

posted @ 2021-07-08 13:48  CodeSweet  阅读(124)  评论(0编辑  收藏  举报