问题1
@Data其实已经包含@EqualsAndHashCode了,哪么有些场景 类上使用了@Data,还要使用@EqualsAndHashCode(callSuper = true)?这是出于什么目的呢?
分析
@Data已经包含@EqualAndHashCode,如下所示:
@EqualsAndHashCode的callSuper属性默认为false,即生成的equals函数并不会考虑父类,看下面代码Child1和Child2类的反编译
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class LombokDataTest {
@Data
public static class Parent {
private static String C_P = "P";
private Long id;
}
@Data
public class Child1 extends Parent {
private String name;
public Child1(Long id, String name) {
setId(id);
setName(name);
}
}
@Data
@EqualsAndHashCode(callSuper = true)
public class Child2 extends Parent {
private String name;
public Child2(Long id, String name) {
setId(id);
setName(name);
}
}
@Test
public void testData() {
Child1 c11 = new Child1(0L, "n");
Child1 c12 = new Child1(1L, "n");
Assertions.assertEquals(c11, c12, "name相等 就应该 equals");
Child2 c21 = new Child2(0L, "n");
Child2 c22 = new Child2(1L, "n");
Assertions.assertNotEquals(c21, c22, "因为加了EqualsAndHashCode,id、name都相等 才equals");
}
}
如上所示,Child2加了@EqualsAndHashCode(callSuper = true),若要equals为true,还需要super.equals为true即行,即父类属性 也相等才行;
上面代码中 测试函数也反应了这个问题;
问题2
@EqualsAndHashCode(callSuper = true)可以进行传递吗?
看下面代码,C1继承Parent并没有加@EqualsAndHashCode(callSuper = true),但C2继承C1并设置了true,哪么C2的equals里会 考虑 Parent类的id属性吗?
根据上面分析,是通过super.equals来实现的,但C1类中equals并没有考虑super.equals, 因此并不会考虑Parent的属性,下面测试函数也证明了
@Data
public class C1 extends Parent {
private String name;
}
@Data
@EqualsAndHashCode(callSuper = true)
public class C2 extends C1 {
private int age;
public C2(Long id, String name, int age) {
setId(id);
setName(name);
setAge(age);
}
}
@Test
public void testEqualsAndHashCode继承传递() {
C2 c1 = new C2(0L, "n", 10);
C2 c2 = new C2(1L, "n", 10);
Assertions.assertEquals(c1, c2);
}
结论
1.使用@Data时,若涉及equals和hashCode,并且要考虑parent属性,则要加上@EqualsAndHashCode(callSuper = true),否则会导致判断错误(本来不相等,却被判为相等);
2.当前类的@EqualsAndHashCode不会影响其父类的@EqualsAndHashCode;
3.对于注解@EqualsAndHashCode,对 hashCode函数 的处理 类似equals