Lombok的@Data、@Accessors、@EqualsAndHashCode使用细节
Java编辑器现在有一个Lombok的插件,使用非常方便,IDEA、Eclipse都有对应的插件。
Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
实际项目中看到如下使用片段:
/**
* xx信息
*
* @Author wanglingqiang
* @Date 2020/6/30 上午10:01
**/
@Data
@ApiModel(value = "Team(xx信息)")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class Team implements Serializable {
private static final long serialVersionUID = 7618841591717042342L;
// ...其他类属性
类上Lombok相关的注解有:
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
Entity、DTO、VO类建好后,如上的注解大家都是直接拷贝(至于这些注解都是干嘛的,不知道!别人这么用,我也这么用呗)。但心里还是不放心,于是自己写Demo测试了一下。
@Data:是Lombok的基础注解,这个不用说了。
接下来说说另外两个注解:
@Accessors注解
@Accessors(chain = true)
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Accessors {
boolean fluent() default false;
boolean chain() default false;
String[] prefix() default {};
}
源码默认是false,我们代码里设置了true。有什么区别呢?直接上图说明:
值为true时 setXxx()方法。
值为false时 setXxx()方法。
发现了没,setXxx()方法的返回值不同,chain=true表示链路开启,setXxx()操作后返回对象,可以继续做其他操作。
@Accessors(fluent = true)
又是什么意思呢?直接上图说明:
getXxx()方法变成了xxx()。
setXxx(String xx)方法变成了xxx(String xx)。
@Accessors(fluent = true) 总结,也即去掉get、set的前缀,直接使用类属性。
@Accessors(prefix = “xxx”)
点进源码,我们看到@Accessors还有prefix这个属性,从语义上理解是前缀的意思,我们来试试它怎么实现前缀的。
没加prefix属性前,可以看到是常规的getXxx()、setXxx()。然后对teamNo属性加上前缀:
@Accessors(prefix = "team")
private String teamNo;
再看看teamNo属性的getXxx()、setXxx() ,如下:
发现了没,teamNo生成的getXxx()、setXxx()去掉了prefix = "team"的“team”前缀。
@EqualsAndHashCode
接下来,再看看我们代码里的 @EqualsAndHashCode(callSuper = false)是什么用意。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
String[] exclude() default {};
String[] of() default {};
boolean callSuper() default false;
boolean doNotUseGetters() default false;
可以看出,源码里callSuper默认值就是false,所以说我们代码里面写这一行是多余的。
然后,再看看callSuper的作用,查找资料给的解释是,在重写hashcode()和equals()方法时是否调用父类的属性。是不是是懂非懂,直接上图说明:
父类Page:
/**
* 分页公共类
*
* @author wanglingqiang
* @date 2020/7/16 下午6:25
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Page {
/**
* 当前页
*/
private Integer current = 1;
/**
* 每页数量
*/
private Integer size = 10;
}
子类User,继承Page(callSuper默认值是false,所以这里就没写):
/**
* 用户查询DTO
*
* @author wanglingqiang
* @date 2020/7/16 下午6:27
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends Page {
private Integer id;
private String name;
public User(Integer current, Integer size, Integer id, String name) {
super(current, size);
this.id = id;
this.name = name;
}
}
测试类Test:
/**
* 测试类
*
* @author wanglingqiang
* @date 2020/7/16 下午6:29
**/
public class Test {
public static void main(String[] args) {
User user1 = new User(1, 10, 1, "张三");
User user2 = new User(2, 10, 1, "张三");
boolean flag = user1.equals(user2);
System.out.println("flag = " + flag);
}
}
@EqualsAndHashCode(callSuper = false)时,运行结果:
flag = true
奇怪不,明明属性值不一样,但equal()比较时竟然相等。
@EqualsAndHashCode(callSuper = true)时,运行结果:
flag = false
可以看出,callSuper = true时,子类在重写hashcode()和equals()方法时才会调用父类的属性,即把父类属性包含在一起重写hashcode()和equals()方法。
callSuper有它的实用场景,为true、为false可以根据实际需要设值。
扩展:
上面的示例中我们还演示了另外两个Lombok注释:
@NoArgsConstructor
@AllArgsConstructor
这两个注解比较加单,从语义上就能理解,是生成构造方法用的。写上这两个注解的效果,如图:
本文地址:https://blog.csdn.net/WLQ0621/article/details/107388831