目录
  1. 1. lombok使用可能遇到的坑
    1. 1.1. 常用注解
    2. 1.2. 工作原理:
    3. 1.3. @EqualsAndHashCode的坑:
      1. 1.3.1. 测试父类:
      2. 1.3.2. 测试子类:
      3. 1.3.3. main函数:
      4. 1.3.4. 运行结果:
      5. 1.3.5. 反编译后的 equals 代码:
    4. 1.4. 总结
lombok使用可能遇到的坑

lombok使用可能遇到的坑

参考链接:https://www.bianxiaofeng.com/article/78

无意间逛博客发现一个以前在项目中看到的注解,当时还不理解为什要加@EqualsAndHashCode(callSuper = true),正好写个例子记录一下。

常用注解

在日常使用中会经常用到以下注解:

  1. @Data: 用在类上,用于生成setter/getter/equals/canEqual/hashCode/toString 方法,如果字段为final属性则不会为它生成get/set方法.
  2. @Setter 用在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
  3. @Getter 用在类或字段,注解在类时为所有字段生成getter方法,注解在字段上时只为该字段生成getter方法。
  4. @ToString 用在类上,用于生成toString方法。
  5. @EqualsAndHashCode 用在类上,生成hashCode和equals方法。
  6. @NoArgsConstructor 用在类上,生成无参的构造方法。
  7. @RequiredArgsConstructor 用在类上,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
  8. @AllArgsConstructor 用在类上,生成包含类中所有字段的构造方法。
  9. @Slf4j 用在类上,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);
  • 平常我使用的时候只是在实体类上加一个@Data,它包括了setter、getter、toString、EqualsAndHashCode等。

工作原理:

​ 在使用Javac进行编译的过程中会先对源代码进行分析,生成一个抽象语法树(AST),然后调用实现了”JSR 269 API”的Lombok程序,接着之前生成的抽象语法树进行处理,在使用了@Data等注解的类的语法树上进行修改,追加相应的get/set方法的对应数节点.然后使用修改后的抽象语法树生成字节码.

@EqualsAndHashCode的坑:

举个例子,编写一个父类和一个继承它的子类。

测试父类:

1
2
3
4
5
6
7
8
9
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestSuper {

private Integer id;

private String name;
}

测试子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Data
public class AppleTestSuper extends TestSuper{

private String code;

private Integer age;

public AppleTestSuper(Integer id,String name,String code,Integer age){
super(id,name);
this.code=code;
this.age=age;
}
}

main函数:

1
2
3
4
5
6
7
8
9
public class TestMain {

public static void main(String[] args) {
AppleTestSuper appleTestSuper = new AppleTestSuper(1,"ccc","321",11);
AppleTestSuper appleTestSuper1 = new AppleTestSuper(2,"ccc","321",11);

System.out.println(appleTestSuper.equals(appleTestSuper1));
}
}

运行结果:

true

很明显不相等的两个类为什么equals返回为true,正好学习了一下如何反编译class文件,IDEA编译器自带了反编译的工具,可以在setting里的plugins里搜索byte看到下图

image-1

或者下载一个JD-GUI,也叫Java Decompiler,直接打开class文件就能反编译成java文件了

image-2

反编译后的 equals 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof AppleTestSuper)) {
return false;
} else {
AppleTestSuper other = (AppleTestSuper)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$code = this.getCode();
Object other$code = other.getCode();
if (this$code == null) {
if (other$code != null) {
return false;
}
} else if (!this$code.equals(other$code)) {
return false;
}

Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age != null) {
return false;
}
} else if (!this$age.equals(other$age)) {
return false;
}

return true;
}
}
}

可以看到,这里只比较了子类中的两个属性,并未比较父类中的属性,所以我们会发生上面的错误

Lombok有@EqualsAndHashCode注解,而@Data这一个注解就包括了@EqualAndHashCode,而@EqualAndHashCode这个注解中有一个callSuper属性,这个属性就是用于判断是否需要在子类的equals方法中加入父类字段的判断,而该属性的默认值为false.

所以在AppleComputer类上添加@EqualsAndHashCode(callSuper = true)后再运行下main方法,结果为false.

再次反编译后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof AppleTestSuper)) {
return false;
} else {
AppleTestSuper other = (AppleTestSuper)o;
if (!other.canEqual(this)) {
return false;
} else if (!super.equals(o)) {
return false;
} else {
Object this$code = this.getCode();
Object other$code = other.getCode();
if (this$code == null) {
if (other$code != null) {
return false;
}
} else if (!this$code.equals(other$code)) {
return false;
}

Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age != null) {
return false;
}
} else if (!this$age.equals(other$age)) {
return false;
}

return true;
}
}
}

可以看到多了一句 if-else 的判断父类的语句,这样就正常了。

总结

在继承父类的子类中我们不仅要加@Data,同时也要@EqualsAndHashCode(callSuper = true),这样做就完全o鸡儿k了。

文章作者: Archiver
文章链接: https://www.kaiming66.com/2020/01/15/Java/lombok%E7%9A%84%E5%9D%91/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Archiver`s Blog
打赏
  • 微信
  • 支付寶

评论