@EqualsAndHashCode
轻松实现相等性:从对象的字段生成 hashCode
和 equals
实现。
概述
任何类定义都可以使用 @EqualsAndHashCode
注解,以让 lombok 生成 equals(Object other)
和 hashCode()
方法的实现。默认情况下,它将使用所有非静态、非瞬态字段,但您可以通过使用 @EqualsAndHashCode.Include
或 @EqualsAndHashCode.Exclude
标记类型成员来修改要使用的字段(甚至指定要使用各种方法的输出)。或者,您可以标记要使用的字段或方法,使用 @EqualsAndHashCode.Include
标记它们,并使用 @EqualsAndHashCode(onlyExplicitlyIncluded = true)
。
如果将 @EqualsAndHashCode
应用于扩展另一个类的类,则此功能会变得有点棘手。通常,为此类类自动生成 equals
和 hashCode
方法是一个坏主意,因为超类也定义了字段,这些字段也需要 equals/hashCode 代码,但此代码不会生成。通过将 callSuper
设置为 true,您可以将超类的 equals
和 hashCode
方法包含在生成的方法中。对于 hashCode
,super.hashCode()
的结果包含在哈希算法中,对于 equals
,如果超类实现认为它与传入的对象不相等,则生成的方法将返回 false。请注意,并非所有 equals
实现都能正确处理这种情况。但是,lombok 生成的 equals
实现确实能正确处理这种情况,因此如果您的超类也具有 lombok 生成的 equals
方法,您可以安全地调用超类的 equals。如果您有一个显式的超类,则必须为 callSuper
提供某个值,以确认您已考虑过它;否则将导致警告。
当您不扩展任何内容(您扩展 java.lang.Object
)时,将 callSuper
设置为 true 是一个编译时错误,因为它会将生成的 equals()
和 hashCode()
实现变成与简单地从 java.lang.Object
继承这些方法相同的行为:只有相同的对象才会彼此相等并且具有相同的 hashCode。当您扩展另一个类时,不将 callSuper
设置为 true 会生成警告,因为除非超类没有(对相等性重要的)字段,否则 lombok 无法为您生成一个考虑到超类声明的字段的实现。您需要编写自己的实现,或依赖 callSuper
链接工具。您还可以使用 lombok.equalsAndHashCode.callSuper
配置键。
请注意,lombok 仅将 .equals()
实现推迟到所有对象,除了 基本类型和数组。一些众所周知的类型可能具有令人惊讶的 equals 实现。例如,java.math.BigDecimal
考虑了比例,即根据 BigDecimal
自己的 equals
实现,1E2
不等于 100
。
注意: 通过编写一个返回映射值并使用 @EqualsAndHashCode.Include(replaces = "fieldName")
注解它的方法,很容易覆盖任何字段的 equals 行为。例如,为了解决 BigDecimal
相等性问题,您可以编写 @EqualsAndHashCode.Include BigDecimal fieldName() { return fieldName.stripTrailingZeros(); }
。
Lombok 0.10 中的新功能:除非您的类是 final
并且扩展了 java.lang.Object
,否则 lombok 会生成一个 canEqual
方法,这意味着 JPA 代理仍然可以等于其基类,但添加新状态的子类不会破坏 equals 约定。为什么需要这种方法的复杂原因在这篇论文中解释:如何在 Java 中编写 Equals 方法。如果层次结构中的所有类都是 scala case 类和带有 lombok 生成的 equals 方法的类的混合体,则所有相等性都将“正常工作”。如果您需要编写自己的 equals 方法,如果更改 equals
和 hashCode
,则应始终覆盖 canEqual
。
Lombok 1.14.0 中的新功能:要在 equals
(以及相关的 canEqual
)方法的 other
参数上放置注解,您可以使用 onParam=@__({@AnnotationsHere})
。但请小心!这是一个实验性功能。有关更多详细信息,请参阅 onX 功能的文档。
Lombok 1.18.16 中的新功能:可以通过将 cacheStrategy
设置为 CacheStrategy.NEVER
以外的值来缓存生成的 hashCode()
的结果。如果带注解的类的对象可以以任何可能导致 hashCode()
结果更改的方式修改,请勿使用此功能。
使用 Lombok
import lombok.EqualsAndHashCode;
|
原生 Java
import java.util.Arrays;
|
支持的配置键
-
lombok.equalsAndHashCode.doNotUseGetters
= [true
|false
] (默认值: false) - 如果设置为
true
,则 lombok 在生成equals
和hashCode
方法时,将直接访问字段,而不是使用 getter(如果可用)。注解参数 'doNotUseGetters
'(如果显式指定)优先于此设置。 -
lombok.equalsAndHashCode.callSuper
= [call
|skip
|warn
] (默认值: warn) - 如果设置为
call
,则当您的类扩展了其他类时,lombok 将生成对hashCode
和equals
的超类实现的调用。如果设置为skip
,则不会生成此类调用。默认行为类似于skip
,但会发出额外的警告。 -
lombok.equalsAndHashCode.flagUsage
= [warning
|error
] (默认值: 未设置) - 如果配置了,Lombok 将把任何
@EqualsAndHashCode
的使用标记为警告或错误。
小字印刷
数组是“深度”比较/哈希编码的,这意味着包含自身的数组将导致 StackOverflowError
。但是,此行为与例如 ArrayList
没有什么不同。
您可以安全地推测,所使用的 hashCode 实现不会在 lombok 版本之间更改,但是此保证并非一成不变;如果可以通过使用替代哈希算法获得显着的性能提升,则将在未来的版本中替换它。
为了相等性的目的,浮点数和双精度数的 2 个 NaN
(非数字)值被认为是相等的,即使 “NaN == NaN” 会返回 false。这类似于 java.lang.Double
的 equals 方法,并且实际上是必需的,以确保将对象与其自身的精确副本进行比较时,相等性返回 true
。
如果存在任何名为 hashCode
或 equals
的方法,无论返回类型如何,都不会生成任何方法,并且会发出警告。这 2 个方法需要彼此同步,除非 lombok 生成所有方法,否则 lombok 无法保证这一点,因此如果其中一个或两个方法已存在,您始终会收到警告。您可以将任何方法标记为 @lombok.experimental.Tolerate
以将其从 lombok 中隐藏。
尝试排除不存在或无论如何都会被排除的字段(因为它们是静态的或瞬态的)会导致在命名字段上发出警告。
如果一个方法被标记为包含,并且它与一个字段同名,它将替换该字段(该方法被包含,该字段被排除)。
在 lombok 1.16.22 之前,可以使用 @EqualsAndHashCode
注解的 of
和 exclude
参数完成包含/排除。这种旧式的包含机制仍然受支持,但将来将被弃用。
默认情况下,任何以 $ 符号开头的变量都会自动排除。您只能通过使用 @EqualsAndHashCode.Include
标记它们来包含它们。
如果存在要包含的字段的 getter,则会调用 getter 而不是使用直接字段引用。此行为可以被抑制
@EqualsAndHashCode(doNotUseGetters = true)
如果您通过 lombok.config
键 lombok.addNullAnnotations
配置了空值注解风格,则生成的 equals
方法以及任何 canEqual
方法的参数都使用可空注解进行注解。如果您将 @NonNullByDefault
样式注解与严格的空值检查结合使用,则这是必需的。