Lombok:等于子类中的字符串实例变量

Lombok: Equals for string instance variables in subclass

我最近偶然发现 Lombok 并想测试它,当我 运行 遇到这个小问题时。

假设我有

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Name extends AbstractName {

    @NonNull
    private String firstname;

    @NonNull
    private String lastname;

}

其中 AbstractName 是空摘要 class。我想用

测试 equals 方法
@Test
public void testEquals() {
    Name instance1 = new Name("Vorname","Nachname");
    Name instance2 = new Name("Vorname","Nachname");
    boolean expResult = true;
    boolean result = instance1.equals(instance2);
    assertEquals(expResult, result);
}

如您所见,我希望 Name 的两个实例相等。如果你添加

System.out.println(instance1.getFirstname().equals(instance2.getFirstname()));
System.out.println(instance1.getLastname().equals(instance2.getLastname()));

一个得到

true
true

那么,为什么测试失败了?是继承AbstractNamehashCode()问题吗?我该如何解决?

顺便说一句,它不会失败,如果 Name 是一个独立的 class 而不是 AbstractName 的子 class。


原版 Java

这是 Lombok

创建的代码
@java.lang.Override
@java.lang.SuppressWarnings("all")
@lombok.Generated
public boolean equals(final java.lang.Object o) {
    if (o == this) return true;
    if (!(o instanceof Name)) return false;
    final Name other = (Name) o;
    if (!other.canEqual((java.lang.Object) this)) return false;
    if (!super.equals(o)) return false;
    final java.lang.Object this$firstname = this.getFirstname();
    final java.lang.Object other$firstname = other.getFirstname();
    if (this$firstname == null ? other$firstname != null : !this$firstname.equals(other$firstname)) return false;
    final java.lang.Object this$lastname = this.getLastname();
    final java.lang.Object other$lastname = other.getLastname();
    if (this$lastname == null ? other$lastname != null : !this$lastname.equals(other$lastname)) return false;
    return true;
}

使用@Data 是一种快捷方式,其中包括@EqualsAndHashCode。尝试显式添加 @EqualsAndHashCode 并将 callSuper 设置为 false。

但是,对于 long-term 维护,覆盖基础 class 中的 equals/hashCode 和 return true/0 可能更安全,或者应用 @ EqualsAndHashCode 为基数 class.

那么,为什么测试失败了呢?是不是继承了AbstractName导致的hashCode()问题?我该如何解决? 顺便说一句,它不会失败,如果 Name 是独立的 class 而不是 AbstractName

的子class

详细说明为什么当 callSuper 为 True 时测试会失败。

假设您有一个 Child class,它扩展了一个抽象 class。 (或与此相关的任何其他 class)

Name.java:

@EqualsAndHashCode(callSuper = true)
public class Name extends AbstractName {

摘要Name.java:

public class AbstractName {
//some fields

现在,当我们比较具有相同值的 Name.java 的 2 个实例时,因为我们正在使用 Name.java 中的 @EqualsAndHashCode lombok 注释覆盖 equals() 和 hashcode() 方法,所以正确检查值。但是由于我们没有覆盖 AbstractName.java 中的 equals() 和 hashcode() 方法,所以默认情况下 equals() 将始终失败,即使属性的值相同(除非 AbstractName 的 object实例指向相同的 object 引用)

因此,一种选择是在 Child class 中制作 @EqualsAndHashCode(callSuper = false)。但是parentclass(AbstractName.java)中的字段不会被比较

解决方案:- 更好的选择是在 Name.java 中添加 @EqualsAndHashCode(callSuper = true) 并在 AbstractName.java 中添加 @EqualsAndHashCode 以便覆盖 equals() 和 hashcode()在 parent 和 child class 中,以便正确比较所有 class 中的字段