在项目开发时,有实体类继承了基类,切面中想用基类的字段往数据库写,但是发现基类的get set没有被@Data创建出来。上网查了一下,以下记录。
原文链接:https://blog.csdn.net/huluwa10526/article/details/108845383
@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加一点点业务代码(但通常不建议这么加),能极大的简化某些业务场景的代码。
用还是不用,这中间如何取舍,自然是要看项目的需要,灵活运用。
原文链接:https://blog.csdn.net/huluwa10526/article/details/108845383