为什么重写equals 和 hashcode 方法,lombok中@EqualsAndHashCode(callSuper = false/true) 什么区别

发布时间 2024-01-11 23:11:09作者: 大阿张

前言

一开始学习 java 的时候,当我们在定义一个 pojo 的时候,都会去重写 equals 和 hashcode 方法。我已经忘记了当时是怎么学习的,反正感觉当时并没有很清晰的认知到重写equals 和 hashcode 的意义是什么,只是简单的背了一些八股文,包括在学习 Map的时候,也并没有很关心这一点。
目前已经工作一年时间了,平常直接一个lombok的@Data注解就搞定一个 pojo ,所以今天好好的复习一下

为什么要重写 equals 方法

java中的类都隐式的继承于Object这个父类,在 Object 类中就有 equals 和 hashcode 方法。在Object 类中的 equals 方法,是直接比较引用值:

 public boolean equals(Object obj) {
        return (this == obj);
    }

思考下面一个情景,当我们有一个类 Student ,里面有 name,age属性如下:

public class Student {

    private String name;
    private Integer age;
	// ......
}

那么我使用 new 关键字创建两个学生对象时:
new Student("zhangsan",12)
new Student("zhangsan",12)
然后使用 equals方法去比较,这个时候比较的是对象的引用值,而这两个对象的引用值肯定是不等的,所以结果是 false,可是这和我们实际业务,或实际认知中的有矛盾,我明明同一个类的两个对象的属性值都一样,使用equals 方法比较的结果却是 false,为了解决这个问题,所以需要对 equals方法进行重写。

  @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name) && Objects.equals(age, student.age);
    }

为什么重写了 equals 方法一定要重写 hashcode 方法

在 java中有通用的约定:

  • 在java应用程序运行时,无论何时多次调用同一个对象时的hsahCode()方法,这个对象的hashCode()方法的返回值必须是相同的一个int值。
  • 如果两个对象equals()返回值为true,则他们的hashCode()也必须返回相同的int值。
  • 如果两个对象equals()返回值为false,则他们的hashCode()返回值也必须不同。

我们都知道Set 首先会通过对象的hashcode 定位数组的索引,如果这个位置没有元素则直接放入,如果有元素即发生了hash冲突,则使用equals方法比较,为true则丢弃,为false则形成链表插入。

如果重写了equals方法,而没有重写 hashcode方法,就可能造成,把两个相等的对象全部存入 Set 中,这是矛盾的,所以重写equals 必须重写hashcode

lombok 中@EqualsAndHashCode(callSuper = false/true) 什么区别

其实就是当一个类继承自一个父类时,如果callSuper=true,那么生成的equals和 hashcode方法会讲父类中的属性包括,默认callSuper =false

@Data
@EqualsAndHashCode(callSuper = false)
public class EHSubClass extends EHSuperClass{
    private String name;
    private String addr;
}

@Data
public class EHSuperClass {

    private Boolean isDel;

    public static void main(String[] args) {
        EHSubClass ehSubClass = new EHSubClass();
        ehSubClass.setAddr("beijing");

        EHSubClass ehSubClass1 = new EHSubClass();
        ehSubClass1.setAddr("beijing");
        ehSubClass1.setIsDel(false);
		// callSuper =false 时结果为true, callSuper =true时,结果为false
        System.out.println(ehSubClass1.equals(ehSubClass));
    }
}