Lombok 的 @Data 注解会帮我们实现 equals 和 hashcode 方法,但是有继承关系时, Lombok 自动生成的方法可能就不是我们期望的了。
我们先来研究一下其实现:定义一个 Person 类型,包含姓名和身份证两个字段:
1 2 3 4 5 6 7 8 9 10 11 12 @Data class Person { private String name; private String identity; public Person () {} public Person (String name, String identity) { this .name = name; this .identity = identity; } }
对于身份证相同、姓名不同的两个 Person 对象:
1 2 3 Person person1 = new Person("zhuye" ,"001" ); Person person2 = new Person("Joseph" ,"001" ); log.info("person1.equals(person2) ? {}" , person1.equals(person2));
使用 equals 判等会得到 false。如果你希望只要身份证一致就认为是同一个人的话,可以使用 @EqualsAndHashCode.Exclude 注解来修饰 name 字段,从 equals 和 hashCode 的实现中排除 name 字段:
1 2 @EqualsAndHashCode .Excludeprivate String name;
修改后得到 true。打开编译后的代码可以看到,Lombok 为 Person 生成的 equals 方法的实现,确实只包含了 identity 属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public boolean equals (final Object o) { if (o == this ) { return true ; } else if (!(o instanceof LombokEquealsController.Person)) { return false ; } else { LombokEquealsController.Person other = (LombokEquealsController.Person) if (!other.canEqual(this )) { return false ; } else { Object this $identity = this .getIdentity(); Object other$identity = other.getIdentity(); if (this $identity == null ) { if (other$identity != null ) { return false ; } } else if (!this $identity.equals(other$identity)) { return false ; } return true ; } } }
但到这里还没完,如果类型之间有继承,Lombok 会怎么处理子类的 equals 和 hashCode 呢?我们来测试一下,写一个 Employee 类继承 Person,并新定义一个公司属性:
1 2 3 4 5 6 7 8 @Data public class Employee extends Person { private String company; public Employee (String name, String identity, String company) { super (name, identity); this .company = company; } }
在如下的测试代码中,声明两个 Employee 实例,它们具有相同的公司名称,但姓名和身份证均不同:
1 2 3 Employee employee1 = new Employee("zhuye" ,"001" , "bkjk.com" ); Employee employee2 = new Employee("Joseph" ,"002" , "bkjk.com" ); log.info("employee1.equals(employee2) ? {}" , employee1.equals(employee2));
很遗憾,结果是 true,显然是没有考虑父类的属性,而认为这两个员工是同一人,说明 @EqualsAndHashCode 默认实现没有使用父类属性。
为解决这个问题,我们可以手动设置 callSuper 开关为 true,来覆盖这种默认行为:
1 2 3 4 5 @Data @EqualsAndHashCode (callSuper = true )public class Employee extends Person { }
修改后的代码,实现了同时以子类的属性 company 加上父类中的属性 identity,作为 equals 和 hashCode 方法的实现条件(实现上其实是调用了父类的 equals 和 hashCode)。