在项目开发时,有实体类继承了基类,切面中想用基类的字段往数据库写,但是发现基类的get set没有被@Data创建出来。上网查了一下,看到一篇关于父子类的属性冲突的记录一下。


 

※.首先想创建出父类的get set,要在父类上也加@Data,父类不加data注解,在用子实例类调用时是调不到父类属性的。

 

@Data取代Get,Set方法的使用总结以及注意事项

前言:

开发过程中发现前辈的代码中实体类没有任何get,set方法但是却能正常使用get,set方法,仔细研究发现每个实体类中都使用了@Data 注解于是仔细研究了下@Data的使用方法。

介绍:

@Data 注解的主要作用是提高代码的简洁,使用这个注解可以省去代码中大量的get()、 set()、 toString()等方法;

使用:

要使用 @Data 注解要先引入lombok工具类库,可以用简单的注解形式来简化代码,提高开发效率。

在maven中添加依赖

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>1.18.4</version>

<scope>provided</scope>

</dependency>


注意!

在编译器中添加插件

这里以IDEA为例,在setting的plugin里搜索lombok plugin,安装插件。重启即可。

接下来就是写实体类的时候就可以直接使用这个标签了!

例如:

@Data

public class UsersDto {

@Id

private Integer id;

private String name;

private String password;

/**

* 性别 0男生 1女生

*/

private Byte sex;

private String email;

private String city;

}


常用的几个注解:

@Data : 注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法

@AllArgsConstructor : 注在类上,提供类的全参构造

@NoArgsConstructor : 注在类上,提供类的无参构造

@Setter : 注在属性上,提供 set 方法

@Getter : 注在属性上,提供 get 方法

@EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法

@Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log

这样使用是不是很方便?

但是!

多年的经验告诉我,有失就有得,为什么这么好用的标签没有大面积使用呢?于是乎我深入研究了一下这个标签的使用,发现原来@Data标签还有这么多的注意事项,如果没注意的话,项目很可能出现难以预料的bug而且排查起来也很困难,下面举例说明,也顺便警醒自己和看到这篇文章的大家,如果遇到新的工具,没研究透之前,千万别贸然使用到项目中。

@Data注解它是一个混合注释,它包含了@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode的功能,而我们问题@EqualsAndHashCode是重写equals和hash的注释,如果你是一个类,那可以不关心它;而如果你的类中有继承(父类子类),那么就要注意一下了

package com.*.user;

import lombok.Data;

import lombok.EqualsAndHashCode;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;

import java.util.Objects;

//@RunWith(SpringRunner.class)

//@SpringBootTest

public class LombokTest {

@Data

class Person {

String name;

int age;

}

@Data

//重写时带上父类字段

@EqualsAndHashCode(callSuper = true)

class Man extends Person {

Boolean hunting;

}

@Data

//重写equals时不会带上父类的字段,同种类型比较时,当子类字段相同时,结果就为true,这显然是不准确的.

@EqualsAndHashCode(callSuper = false)

class Woman extends Person {

Boolean spin;

}

@Test

public void tsetlombok() {

Man t1 = new Man();

Man t2 = new Man();

t1.setName("123");

t2.setName("12345");

String name = "1";

t1.name = name;

t2.name = name;

int age = 1;

t1.age = age;

t2.age = age;

System.out.println(t1.equals(t2));//true

System.out.println(t2.equals(t1));//true

System.out.println(t1.hashCode());//376050

System.out.println(t2.hashCode());//376050

System.out.println(t1 == t2);//false

System.out.println(Objects.equals(t1, t2));//true

}

@Test

public void supperSubEqual() {

Man man = new Man();

man.setName("小张");

man.setAge(22);

man.setHunting(true);

Man man1 = new Man();

man1.setHunting(true);

man1.setName("小李");

man.setAge(23);

System.out.println("man==man1?"+ man.equals(man1)); // false

Woman woman = new Woman();

woman.setName("小赵");

man.setAge(19);

woman.setSpin(true);

Woman woman1 = new Woman();

woman1.setSpin(true);

man.setAge(18);

woman1.setName("小美");

System.out.println("woman==woman1? "+ woman.equals(woman1)); // true

}

}


@EqualsAndHashCode注解里有个字段callSuper,它的默认值是false,意思是在重写时,不会将父类的字段写到equals里;而@Data这个注解由于包含了@EqualsAndHashCode,所以它也有这个特性,即子类强制实现了重写equals和hashCode,并且只重写了自己的属性,这时,问题就来了,当两个对象比较时,如果子类属性相同而父类属性不同,结果也为true,这是非常严重的bug。

通过以上两个test我们发现:

父类里的字段不相同时,结果应该为false,但如果 @EqualsAndHashCode(callSuper = false),结果竟然是true,这是因为它并没有重写父类的属性name,所以只要子类字段相同,结果就认为相同了。

所以在使用@Data时,我们尽量把 @EqualsAndHashCode(callSuper = true)加上,因为你不加,它相当于是false;

优点:

1、能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率

2、让代码变得简洁,不用过多的去关注相应的方法

3、属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等

缺点:

1、不支持多种参数构造器的重载

2、虽然省去了手动创建getter/setter方法的麻烦,但大大降低了源代码的可读性和完整性

总结:

1、用了@Data就不要有继承关系

2、自己重写equals(), Lombok 不会对显式重写的方法进行生成。

3、显式使用@EqualsAndHashCode(callSuper = true), Lombok 会以显式指定的为准。

4、或者杜绝使用@Data,而用@Getter,@Setter,@ToString代替它。

lombok 只是省去了一些人工生成代码的麻烦,但是这些getter/setter等等的方法,用IDE的快捷键也可很方便的生成。况且,有时通过给getter/setter加一点点业务代码(但通常不建议这么加),能极大的简化某些业务场景的代码。

用还是不用,这中间如何取舍,自然是要看项目的需要,灵活运用。




如有差错,请各位指正