Lombok @EqualsAndHashCode 注解详解

📅 2026/7/8 22:51:27
Lombok @EqualsAndHashCode 注解详解
概述EqualsAndHashCode是 Lombok 提供的一个注解用于自动生成equals()和hashCode()方法。这两个方法在 Java 中非常重要特别是在使用集合类如HashMap、HashSet时。基本用法1. 默认行为importlombok.EqualsAndHashCode;EqualsAndHashCodepublicclassUser{privateStringname;privateIntegerage;privateStringemail;}生成的代码会使用所有非静态、非 transient 字段调用父类的equals()和hashCode()方法遵循标准的 equals/hashCode 契约2. 排除特定字段EqualsAndHashCode(exclude{email})publicclassUser{privateStringname;privateIntegerage;privateStringemail;// 不参与 equals/hashCode 计算}3. 只包含特定字段EqualsAndHashCode(of{name,age})publicclassUser{privateStringname;privateIntegerage;privateStringemail;// 不参与 equals/hashCode 计算}常用参数参数类型说明excludeString[]排除的字段列表ofString[]只包含的字段列表callSuperboolean是否调用父类的 equals/hashCodedoNotUseGettersboolean是否直接访问字段而非使用 getteronlyExplicitlyIncludedboolean只包含显式标记的字段高级用法1. 继承场景EqualsAndHashCode(callSupertrue)publicclassEmployeeextendsPerson{privateStringemployeeId;privateBigDecimalsalary;}注意如果父类没有重写equals()/hashCode()使用callSuper true会导致基于对象引用的比较对于继承体系建议要么在所有子类中都设置callSuper true要么都不设置2. 自定义字段排序EqualsAndHashCodepublicclassProduct{privateStringcategory;EqualsAndHashCode.IncludeprivateStringname;EqualsAndHashCode.ExcludeprivatetransientStringcache;}3. 处理循环引用EqualsAndHashCode(exclude{parent})publicclassTreeNode{privateStringvalue;privateTreeNodeparent;// 排除以避免循环引用privateListTreeNodechildren;}最佳实践✅ 推荐做法保持一致性如果重写了equals()必须同时重写hashCode()使用不可变字段参与 equals/hashCode 的字段应该是不可变的或很少改变EqualsAndHashCodepublicclassOrder{privatefinalStringorderId;// 不可变字段privatefinalLocalDateTimecreateTime;}排除派生字段不要将可以通过其他字段计算得出的字段包含在内EqualsAndHashCode(of{firstName,lastName})publicclassPerson{privateStringfirstName;privateStringlastName;privateStringfullName;// 派生字段应排除}谨慎使用 callSuper// 好的做法 - 明确的继承关系EqualsAndHashCode(callSupertrue)publicclassManagerextendsEmployee{privateListEmployeesubordinates;}❌ 避免的做法不要在可变字段上使用EqualsAndHashCodepublicclassBadExample{privateListStringitems;// 可变集合可能导致 hashCode 变化}不要混合使用 exclude 和 of// 错误编译失败EqualsAndHashCode(exclude{email},of{name,age})publicclassUser{}不要忘记处理 null 值Lombok 会自动处理 null但要确保业务逻辑正确与集合类的关系HashMap 中的使用EqualsAndHashCodepublicclassKey{privateStringid;privateStringtype;}// 正确使用MapKey,StringmapnewHashMap();Keykey1newKey(1,A);Keykey2newKey(1,A);System.out.println(key1.equals(key2));// trueSystem.out.println(key1.hashCode()key2.hashCode());// truemap.put(key1,value1);System.out.println(map.get(key2));// value1 - 能正确找到HashSet 中的去重EqualsAndHashCode(of{email})publicclassUser{privateStringname;privateStringemail;}SetUserusersnewHashSet();users.add(newUser(Alice,aliceexample.com));users.add(newUser(Alice Smith,aliceexample.com));System.out.println(users.size());// 1 - 根据 email 去重性能考虑1. 字段选择影响性能// 性能好 - 使用简单字段EqualsAndHashCode(of{id})publicclassEntity{privateLongid;privateStringname;privatebyte[]data;// 大数据不参与比较}// 性能差 - 包含大对象EqualsAndHashCodepublicclassBadEntity{privateLongid;privatebyte[]largeData;// 每次比较都要遍历整个数组}2. 缓存 hashCode对于频繁用作 HashMap key 的对象可以考虑手动缓存EqualsAndHashCodepublicclassCachedHash{privateStringkey;privatevolatileinthashCode0;OverridepublicinthashCode(){if(hashCode0){hashCodesuper.hashCode();}returnhashCode;}}常见问题Q1: 什么时候应该使用 EqualsAndHashCodeA:当类需要作为 HashMap 的 key 时当类需要存储在 HashSet 中时当需要进行对象相等性比较时对于纯数据类DTO、Entity通常都应该使用Q2: exclude 和 of 有什么区别A:exclude: 排除指定字段其他所有字段都参与of: 只包含指定字段其他字段都排除两者不能同时使用Q3: callSuper 什么时候必须设置为 trueA:当父类已经重写了equals()/hashCode()且你希望包含父类字段时当你的类是某个继承体系的一部分且父类的 equals 有重要业务含义时Q4: 如何处理包含集合字段的类A: Lombok 会自动处理集合的 equals/hashCode但要注意EqualsAndHashCodepublicclassOrder{privateStringorderId;privateListOrderItemitems;// 会递归调用 OrderItem 的 equals}// 确保 OrderItem 也正确实现了 equals/hashCodeEqualsAndHashCodepublicclassOrderItem{privateStringproductId;privateIntegerquantity;}与其他 Lombok 注解的组合与 Data 组合Data// 包含 EqualsAndHashCodepublicclassUser{privateStringname;privateIntegerage;}注意Data默认不包含callSuper true如果需要可以单独添加DataEqualsAndHashCode(callSupertrue)publicclassEmployeeextendsPerson{privateStringemployeeId;}与 Value 组合Value// 不可变类包含 EqualsAndHashCodepublicclassMoney{BigDecimalamount;Stringcurrency;}与 Builder 组合BuilderEqualsAndHashCode(of{id})publicclassProduct{privatefinalStringid;privatefinalStringname;privatefinalBigDecimalprice;}总结EqualsAndHashCode是 Lombok 中最实用的注解之一它可以减少样板代码自动生成标准的 equals/hashCode 实现避免常见错误确保两个方法的一致性提高可维护性字段变更时无需手动更新方法灵活配置支持排除、包含、调用父类等选项核心原则始终保证 equals 和 hashCode 的一致性谨慎选择参与比较的字段考虑性能和业务语义在继承体系中保持策略一致