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

这两个注解比较加单,从语义上就能理解,是生成构造方法用的。写上这两个注解的效果,如图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/WLQ0621/article/details/107388831