lombok @EqualsAndHashCode 注解的影响

本文详细解析Lombok注解@Data和@EqualsAndHashCode的功能与潜在问题,特别是当继承父类时equals和hashCode方法的实现差异。提供了解决方案,包括自定义equals和hashCode方法或使用@EqualsAndHashCode(callSuper=true)。

官方文档:@EqualsAndHashCode

原文中提到的大致有以下几点:

  1. 此注解会生成equals(Object other) 和 hashCode()方法。
  2. 它默认使用非静态,非瞬态的属性
  3. 可通过参数exclude排除一些属性
  4. 可通过参数of指定仅使用哪些属性
  5. 它默认仅使用该类中定义的属性且不调用父类的方法
  6. 可通过callSuper=true解决上一点问题。让其生成的方法中调用父类的方法。

另:@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集。

通过官方文档,可以得知,当使用@Data注解时,则有了@EqualsAndHashCode注解,那么就会在此类中存在equals(Object other) 和 hashCode()方法,且不会使用父类的属性,这就导致了可能的问题。
比如,有多个类有相同的部分属性,把它们定义到父类中,恰好id(数据库主键)也在父类中,那么就会存在部分对象在比较时,它们并不相等,却因为lombok自动生成的equals(Object other) 和 hashCode()方法判定为相等,从而导致出错。

修复此问题的方法很简单:

  1. 使用@Getter @Setter @ToString代替@Data并且自定义equals(Object other) 和 hashCode()方法,比如有些类只需要判断主键id是否相等即足矣。
  2. 或者使用在使用@Data时同时加上@EqualsAndHashCode(callSuper=true)注解。
    原文:https://blog.youkuaiyun.com/zhanlanmg/article/details/50392266
<think>我们正在讨论的是Lombok库中的@EqualsAndHashCode注解。根据引用内容,这个注解的主要作用是自动生成equals()和hashCode()方法。 在Java中,equals()和hashCode()方法非常重要,特别是在使用集合框架(如HashSet, HashMap等)时,因为它们依赖于这些方法来正确比较对象和计算哈希值。 具体作用: 1. 自动生成equals()方法:该方法用于比较两个对象是否相等。默认情况下,Java中的equals()方法比较的是对象引用(即内存地址),而我们需要根据业务逻辑比较对象的内容。@EqualsAndHashCode注解会根据类的字段生成比较内容是否相等的equals方法。 2. 自动生成hashCode()方法:该方法返回对象的哈希码值。在哈希表等数据结构中,哈希码用于确定对象的存储位置。如果两个对象相等(根据equals方法),那么它们的hashCode必须相同。 注意点: - 默认情况下,@EqualsAndHashCode会使用所有非静态(non-static)、非瞬态(non-transient)的字段来生成这两个方法(引用[2]和[5])。 - 可以通过参数排除某些字段(exclude)或者指定只使用某些字段(of)。 - 默认不会考虑父类的字段(引用[5])。如果希望将父类的字段也纳入生成的equalshashCode方法中,可以使用`callSuper=true`(引用[4]和[5])。例如:`@EqualsAndHashCode(callSuper = true)` 为什么使用这个注解? - 手动编写equalshashCode方法比较繁琐,且容易出错。使用注解可以自动生成,减少样板代码(引用[1])。 - 保证一致性:自动生成的方法可以确保当两个对象相等时,它们的哈希码一定相等;而不相等的对象则尽量有不同的哈希码(减少碰撞)。 潜在问题: - 继承问题:如果类有父类,且没有设置`callSuper=true`,那么生成的equalshashCode方法不会包含父类的字段。这可能导致问题,例如两个不同子类实例的父类字段相同,而子类字段不同,但被错误地判断为相等(引用[5])。解决方案是使用`@EqualsAndHashCode(callSuper=true)`。 - 当使用@Data注解时,它包含了@EqualsAndHashCode,因此要注意同样的问题(引用[5])。 举例说明: 引用[2]中的例子: ```java import lombok.EqualsAndHashCode; @EqualsAndHashCode public class Person { private String name; private int age; } ``` 编译后,会生成equalshashCode方法,其中比较的是name和age字段。 另一个需要注意的是,如果类继承了一个类(比如有一个父类Animal),那么: ```java @EqualsAndHashCode(callSuper = true) public class Person extends Animal { private String name; private int age; } ``` 这样,生成的equalshashCode方法会同时考虑Animal中的字段和Person中的name、age字段。 因此,使用@EqualsAndHashCode注解可以大大简化代码,但要注意处理继承关系。 相关问题: 1. 在什么情况下应该使用@EqualsAndHashCode(callSuper=true)? 2. 如何排除某些字段不参与equalshashCode的生成? 3. 使用@EqualsAndHashCode注解可能导致哪些潜在问题? 4. @Data注解@EqualsAndHashCode的关系是怎样的? </think>### @EqualsAndHashCode注解的作用详解 `@EqualsAndHashCode`是Lombok库提供的核心注解,主要解决Java对象比较和哈希计算的样板代码问题。其核心作用如下: #### 1. **自动生成`equals()`方法** - 根据类的**非静态、非瞬态属性**自动生成逻辑严谨的`equals()`方法 - 实现对象内容的深度比较(而非地址比较) - **示例场景**: ```java Person p1 = new Person("Alice", 30); Person p2 = new Person("Alice", 30); System.out.println(p1.equals(p2)); // 输出 true(内容相同) ``` #### 2. **自动生成`hashCode()`方法** - 基于相同的属性集合生成符合规范的哈希码 - 确保内容相同的对象返回相同哈希码 - **规范要求**: - 若`a.equals(b)==true`,则`a.hashCode() == b.hashCode()` - 哈希码需尽可能离散分布(减少哈希碰撞) #### 3. **关键参数配置** | 参数 | 作用 | 示例 | 必要性 | |---|---|---|---| | `callSuper = true` | 包含父类字段参与计算 | `@EqualsAndHashCode(callSuper=true)` | 继承场景必需[^4][^5] | | `exclude` | 排除指定字段 | `@EqualsAndHashCode(exclude = "id")` | 敏感字段排除 | | `of` | 仅包含指定字段 | `@EqualsAndHashCode(of = {"name"})` | 关键字段聚焦 | #### 4. **典型应用场景** - **集合操作**:确保`HashSet`/`HashMap`正确识别相同内容对象 - **DTO对象**:数据传输对象的内容比较 - **实体类**:数据库实体去重(需排除主键字段) ```java @EqualsAndHashCode(exclude = "id") public class User { private Long id; // 数据库主键(应排除) private String email; // 业务唯一标识 } ``` #### 5. **继承场景特殊处理** - **默认行为**:不包含父类字段(易引发逻辑错误)[^5] - **正确姿势**: ```java @EqualsAndHashCode(callSuper = true) public class Student extends Person { private String studentId; } ``` 此时`equals()`会同时比较`Person`的字段和`Student`的`studentId` #### 6. **与@Data注解关系** - `@Data` = `@Getter + @Setter + @ToString + @EqualsAndHashCode`[^5] - 使用`@Data`时需显式声明`callSuper`参数: ```java @Data @EqualsAndHashCode(callSuper = true) // 必须显式添加 public class Manager extends Employee {} ``` ### ️ 注意事项 1. **继承风险**:未设置`callSuper=true`会导致父类字段被忽略(常见BUG根源)[^5] 2. **瞬态字段**:默认忽略`transient`字段(符合序列化规范) 3. **性能影响**:属性过多时生成的哈希函数可能效率较低(需评估) > 通过自动生成规范化的`equals()`和`hashCode()`,该注解可减少80%的样板代码,同时避免手写实现常见的`NullPointerException`、字段遗漏等错误[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值