zoukankan      html  css  js  c++  java
  • @Data注解使用时的注意事项

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

    原文链接:https://blog.csdn.net/huluwa10526/article/details/108845383

    ※.首先想创建出父类的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加一点点业务代码(但通常不建议这么加),能极大的简化某些业务场景的代码。
    用还是不用,这中间如何取舍,自然是要看项目的需要,灵活运用。

    原文链接:https://blog.csdn.net/huluwa10526/article/details/108845383

    如有差错,请各位指正
  • 相关阅读:
    前后端分离实践 — 如何解决跨域问题
    bower 和 npm 的区别详细介绍
    yeoman-bower-grunt之间的关系
    软件开发环境-开发环境、测试环境、生产环境的区别
    Tomcat下配置JNDI的三种方式
    SSE
    Java动态代理
    Css之Relative
    多线程之——死锁
    JVM
  • 原文地址:https://www.cnblogs.com/Timeouting-Study/p/15348327.html
Copyright © 2011-2022 走看看