不灭的焱

革命尚未成功,同志仍须努力 下载Java21

作者:AlbertWen  添加时间:2026-02-25 20:10:54  修改时间:2026-03-17 17:16:21  分类:08.Java基础  编辑

一、豆包解说

1. 注解的核心作用

@EqualsAndHashCode 是 Lombok 框架提供的注解,它的核心作用是自动为你的 Java 类生成 equals()hashCode() 方法。而 callSuper = true 是这个注解的关键参数,用来控制生成方法时是否考虑父类的属性。

先理解基础概念

  • 默认行为(callSuper = false):如果不写 callSuper,默认值是 false,此时 Lombok 生成的 equals()hashCode() 只会考虑当前类的属性,完全忽略父类的属性。
  • callSuper = true:设置为 true 后,生成的方法会同时考虑当前类的属性 + 父类的属性(准确来说是调用父类的 equals()hashCode() 方法)。

2. 代码示例对比

为了让你更直观理解,我用两个简单的类来演示:

父类

public class Parent {
    private String parentField;

    // 手动写构造器(方便测试)
    public Parent(String parentField) {
        this.parentField = parentField;
    }
}

子类(使用注解)

import lombok.EqualsAndHashCode;

// 关键:callSuper = true
@EqualsAndHashCode(callSuper = true)
public class Child extends Parent {
    private String childField;

    public Child(String parentField, String childField) {
        super(parentField);
        this.childField = childField;
    }

    public static void main(String[] args) {
        Child c1 = new Child("父类属性", "子类属性");
        Child c2 = new Child("父类属性", "子类属性");
        Child c3 = new Child("不同父类属性", "子类属性");

        // callSuper = true 时:
        System.out.println(c1.equals(c2)); // 输出 true(父+子属性都相同)
        System.out.println(c1.equals(c3)); // 输出 false(父类属性不同)

        // 如果 callSuper = false(默认):
        // c1.equals(c3) 会输出 true(只比较子类属性,忽略父类属性,这通常不符合预期)
    }
}

3. 为什么需要 callSuper = true?

当你的子类继承了父类,且父类有自己的属性时:

  • 如果不设置 callSuper = true,生成的 equals()/hashCode() 会 “丢失” 父类属性的对比,导致逻辑错误(比如两个对象父类属性不同,但子类属性相同,却被判定为相等)。
  • 只有设置 callSuper = true,才能保证 equals()/hashCode() 遵循 “相等的对象必须有相同的哈希值,且所有属性(包括父类)都相等” 的规范。

4. 注意事项

  • 这个注解仅对继承自普通类的子类有效;如果父类是 Object(所有类的默认父类),callSuper = true 不会有额外效果(因为 Objectequals() 是比较对象地址,hashCode() 是对象的哈希值)。
  • 必须确保父类的 equals()/hashCode() 是正确实现的(如果父类也用 Lombok,建议同样合理配置 @EqualsAndHashCode)。

总结

  1. @EqualsAndHashCode 自动生成 equals()hashCode() 方法,简化代码编写。
  2. callSuper = true 让生成的方法包含父类属性的对比,避免继承场景下的逻辑错误。
  3. 子类继承有属性的父类时,建议显式设置 callSuper = true,保证方法逻辑的完整性。

 

二、DeepSeek解说

@EqualsAndHashCode(callSuper = true) 的作用

这个注解是 Lombok 提供的,用于自动生成 equals() 和 hashCode() 方法。callSuper = true 参数的作用是:在生成的方法中,调用父类的 equals() 和 hashCode() 方法

为什么要使用 callSuper = true?

当你的类继承自另一个类时,需要决定是否将父类的字段也纳入比较。如果不设置 callSuper = true,Lombok 生成的 equals() 和 hashCode() 只会比较当前类中定义的字段,而忽略父类的字段。

举例说明

场景一:不使用 @EqualsAndHashCode(问题示例)

// 父类
@Data
class Person {
    private String name;
    private int age;
}

// 子类
@Data
class Student extends Person {
    private String studentId;
}

public class Test {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("张三");
        s1.setAge(20);
        s1.setStudentId("S001");
        
        Student s2 = new Student();
        s2.setName("张三");
        s2.setAge(20);
        s2.setStudentId("S002");  // 学号不同
        
        System.out.println(s1.equals(s2));  // 输出: true
        // 预期应该是 false,因为学号不同
        // 但实际比较时忽略了父类字段的比较规则
    }
}

场景二:使用 @EqualsAndHashCode(callSuper = true)

// 父类
@Data
class Person {
    private String name;
    private int age;
}

// 子类 - 正确实现
@Data
@EqualsAndHashCode(callSuper = true)  // 包含父类字段的比较
class Student extends Person {
    private String studentId;
}

public class Test {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("张三");
        s1.setAge(20);
        s1.setStudentId("S001");
        
        Student s2 = new Student();
        s2.setName("张三");
        s2.setAge(20);
        s2.setStudentId("S002");
        
        System.out.println(s1.equals(s2));  // 输出: false ✅
        // 现在会同时比较父类的 name、age 和子类的 studentId
        
        Student s3 = new Student();
        s3.setName("李四");  // 名字不同
        s3.setAge(20);
        s3.setStudentId("S001");
        
        System.out.println(s1.equals(s3));  // 输出: false ✅
        // 父类字段不同,也会返回 false
    }
}

场景三:不使用 callSuper 的隐患

@Data
@EqualsAndHashCode  // 默认 callSuper = false
class Teacher extends Person {
    private String teacherId;
}

public class Test {
    public static void main(String[] args) {
        Teacher t1 = new Teacher();
        t1.setName("王老师");
        t1.setAge(35);
        t1.setTeacherId("T001");
        
        Teacher t2 = new Teacher();
        t2.setName("王老师");
        t2.setAge(35);
        t2.setTeacherId("T002");  // 工号不同
        
        System.out.println(t1.equals(t2));  // 输出: true ⚠️
        // 明明工号不同,却被判定为相等,这通常不是期望的行为
    }
}

使用建议

  1. 继承关系中使用:当类有明确的父类时,通常应该设置 callSuper = true

  2. 根据业务需求决定

    • 如果子类完全继承父类的所有属性,且这些属性都参与相等性判断 → callSuper = true

    • 如果父类只是基类,不参与业务相等性判断 → callSuper = false

  3. JPA/Hibernate 实体类:通常建议使用 callSuper = false,避免代理对象的问题

  4. 警告信息:如果不设置 callSuper = true,Lombok 会给出警告,提醒你可能忽略了父类的字段