深入理解Java对象复制

一、图示

二、MapStruct

pom文件

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.2.0.Final</version>
        </dependency>

        <!-- dozer使用时需要配置xml 文件,不推荐使用性能和 BeanUtils 差不多,使用过程可以参考 https://www.jianshu.com/p/bf8f0e8aee23-->
        <!-- https://mvnrepository.com/artifact/net.sf.dozer/dozer -->
        <!--<dependency>
            <groupId>net.sf.dozer</groupId>
            <artifactId>dozer</artifactId>
            <version>5.5.1</version>
        </dependency>-->

下载插件

插件的作用是为了在本地测试的时候,生成 接口的 impl 文件(生成的文件存在与target包里面)

如果是生产环境的话,和Lombok操作一样,需要在pom文件添加 mapStruct 插件依赖

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <showWarnings>true</showWarnings>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.16</version>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>1.2.0.Final</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>

        </plugins>

    </build>

代码

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Created by yangLongFei on 2021/5/11 10:44
 * Version: $
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName
public class Student {
    private Integer id;
    private String name;
    private String age;
    private String phone;
    private String address;
}
import lombok.Data;
import java.io.Serializable;

/**
 * Created by yangLongFei on 2021/5/11 10:51
 * Version: $
 */
@Data
public class StudentDTO implements Serializable {
    private static final long serialVersionUID = 735190899850778343L;
    private Integer id;
    private String name;
    private String age;
    private String phone;
    private String address;
}
import lombok.Data;
import java.io.Serializable;

/**
 * Created by yangLongFei on 2021/5/11 16:59
 * Version: $
 */
@Data
public class StudentVO implements Serializable {
    private static final long serialVersionUID = 2059190505074790405L;

    private Integer pk;
    private String userName;
    private String userAge;
    private String userPhone;
    private String userAddress;
}

接口

import com.sys.yang.dto.StudentDTO;
import com.sys.yang.entity.Student;
import com.sys.yang.vo.StudentVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ConverterStudent {

    ConverterStudent INSTANCE = Mappers.getMapper(ConverterStudent.class);

    @Mappings({
            @Mapping(source = "name", target = "name"),
            @Mapping(source = "age", target = "age")
    })
    StudentDTO entityToDTO(Student student);

    @Mappings({
            @Mapping(source = "id", target = "pk"),
            @Mapping(source = "name", target = "userName"),
            @Mapping(source = "age", target = "userAge"),
            @Mapping(source = "phone", target = "userPhone"),
            @Mapping(source = "address", target = "userAddress")
    })
    StudentVO dtoToVo(StudentDTO studentDTO);

}

测试类 

import com.sys.yang.dto.StudentDTO;
import com.sys.yang.entity.Student;
import com.sys.yang.vo.StudentVO;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import java.lang.reflect.Method;

/**
 * 对象转换,映射
 * 方式1:效率最高 get set 方法
 * 方式2:Common包 BeanUtils.copyProperties 反射的方式进行
 * 方式3:mapstruct 推荐使用,操作不复杂,效率和 get set 方式相差不大
 *
 * <p>
 * Created by yangLongFei on 2021/5/11 10:43
 * Version: $
 */
public class AToB {

    /**
     * set get 的时候使用
     * 生成 对象的set方法
     */
    public static void main(String[] args) {
        Class<StudentDTO> clazz = StudentDTO.class;
        Method[] fields = clazz.getDeclaredMethods();
        for (Method field: fields) {
            String name = field.getName();
            if(!name.startsWith("is") && !name.startsWith("get")){
                System.out.println("entity." + name + "()");
            }
        }
    }

    /**
     * 测试方法
     */
    @Test
    public void test1() {
        Student student = new Student(1,"zhagnsan","18","110112113114","diqiu");
        System.out.println(student.toString());

        StudentDTO studentDTO1 = new StudentDTO();
        BeanUtils.copyProperties(student,studentDTO1);
        System.out.println("BeanUtils: "+ studentDTO1.toString());

        StudentDTO studentDTO2 = ConverterStudent.INSTANCE.entityToDTO(student);
        System.out.println("mapstruct: entityToDTO " + studentDTO2.toString());

        StudentVO studentVO = ConverterStudent.INSTANCE.dtoToVo(studentDTO2);
        System.out.println("mapStruct: dtoToVo "+ studentVO);

    }

}

生成的接口文件

三、framework cglib

要转换的对象的,字段名称 要和 原对象的字段名称一致,否则赋值会失败,可以手动 convert 方法,但是,实现后所有的转换内容都会走 convert 方法

代码

import lombok.Data;

import java.io.Serializable;

/**
 * Created by yangLongFei on 2021/5/11 16:59
 * Version: $
 */
@Data
public class StudentVO implements Serializable {
    private static final long serialVersionUID = 2059190505074790405L;

    private Integer pk;
    private String userName;
    private String userAge;
    private String userPhone;
    private String userAddress;

    // framework cglib 使用到的内容
    private String id;
    private String name;
    private Integer age;
    private String phone;
    private String address;

}

convert 实现类

import org.springframework.cglib.core.Converter;

/**
 * Created by yangLongFei on 2021/5/11 19:53
 * Version: $
 */
public class ConvertStudentDtoToVo implements Converter {

    /**
     * ⭐️⭐️⭐️⭐️⭐️ 要转换的属性名称,相同的情况下,才会走该方法
     * @param o 原对象属性值,value
     * @param aClass 目标对象属性 类型,class java.lang.String
     * @param o1 目标对象属性set方法,setAddress
     * @return
     */
    @Override
    public Object convert(Object o, Class aClass, Object o1) {
        if (o.getClass().equals(aClass)) {
            return o;
        } else {
            if (o instanceof Integer) {
                return String.valueOf(o);
            }
            if (String.valueOf(o1).contains("Age")) {
                return Integer.valueOf(o.toString());
            }
            return o;
        }
    }

}

测试方法

 @Test
    public void test2() {
        Student student = new Student(1,"zhagnsan","18","110112113114","diqiu");

        // false 表示不使用 转换器,
        BeanCopier entityToDto = BeanCopier.create(Student.class, StudentDTO.class, false);
        StudentDTO studentDTO3 = new StudentDTO();
        // null 表示,不指定转换器,要使用转换器的化,需要实现 Converter 接口
        // 属性名称之间不能指定映射关系,当属性名称不同的时候赋值操作会失败
        entityToDto.copy(student, studentDTO3, null);
        System.out.println("cglib :entityToDTO " + studentDTO3.toString());

        BeanCopier dtoTOVo = BeanCopier.create(StudentDTO.class, StudentVO.class, false);
        StudentVO studentVO1 = new StudentVO();
        dtoTOVo.copy(studentDTO3, studentVO1, null);
        System.out.println("cglib: dtoToVo " + studentVO1.toString());

        // 一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性
        BeanCopier dtoTOVo2 = BeanCopier.create(StudentDTO.class, StudentVO.class, true);
        StudentVO studentVO2 = new StudentVO();
        dtoTOVo2.copy(studentDTO3, studentVO2, new ConvertStudentDtoToVo());
        System.out.println("cglib : convert "+studentVO2.toString());

    }

四、问题

beanUtils  不会进行 属性 类型的转换,如果字段名称相同,类型不同,不会对该字段进行赋值操作,( 测试方法中使用的 是 org.springframework.beans.BeanUtils )

cglib  在不定义Converter 的情况下也会出现 类型转换错误的异常,可以手动自定义转换器 convert ,一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性。

springframwork 有实现 cglib 的BeanCopier 不需要再引用 org.easymock 依赖

到此这篇关于深入理解Java对象复制的文章就介绍到这了,更多相关Java对象复制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java对象深复制与浅复制实例详解

     Java对象深复制与浅复制实例详解 我们在遇到一些业务场景的时候经常需要对对象进行复制,对于对象的复制一般有两种方式,深复制和浅复制 浅复制:对象的复制仅是对象本身,对象引用的其它对方并不会复制. 深复制:对象的复制包含对象引用的对象. Java所有对象的基类提供了clone方法,但是这个方法是protected native修饰,因此只暴露给之类去重写,外部是无法直接调用的. 我们现在来测试两种复制,首选是浅复制,浅复制要实现Cloneable接口. // 课程对象 class Class

  • Java中对象的深复制(深克隆)和浅复制(浅克隆)介绍

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵深复制(深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量.那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象.换言之,深复制把要复制的对象所引用的对象都复制了一遍. 2.Java的clone()方法 ⑴clone方法将对象复制了一份并返回

  • 深入java对象复制的分析

    java本身提供了对象复制的能力,在java.lang.Object类中有clone方法,该方法是一个protected方法,在子类需要重写此方法并声明为public类型,而且还需实现Cloneable接口才能提供对象复制的能力,clone()是一个native方法,native方法的效率一般来说都是远高于java中的非native方法,对性能比较关心的话首先考虑这种方式,这种复制在网上有很多例子就不多写了:在这要用的另一种方式--通过java的反射机制复制对象,这种方式效率可能会比clone(

  • Java基础详解之面向对象的那些事儿

    一.面向对象的理解 首先,要清楚一点,与面向过程不同,面向对象有着自己独特的优势.举个通俗的例子,设想我们要得到一把椅子,面向过程的话我们可能需要通过买木材,设计图纸,最后切割而成.但对于面向对象来说,我们只需找到一个家具店,买一把椅子即可. 面向对象也是Java语言的特点之一,其实从idea中不难看出,这种面向对象的语言所具有: 1.易维护 2.易复用 3.易扩展 二.三大特性 2.1 继承(extends): 顾名思义,是获取原有的基础,在此基础上进行操作的一个过程.使用已存在的类的定义作为

  • Java MapStruct解了对象映射的毒

    前言 MVC模式是目前主流项目的标准开发模式,这种模式下框架的分层结构清晰,主要分为Controller,Service,Dao.分层的结构下,各层之间的数据传输要求就会存在差异,我们不能用一个对象来贯穿3层,这样不符合开发规范且不够灵活. 我们常常会遇到层级之间字段格式需求不一致的情况,例如数据库中某个字段是datetime日期格式,这个时间戳在数据库中的存储值为2020-11-06 23:59:59.999999,但是传递给前端的时候要求接口返回yyyy-MM-dd的格式,或者有些数据在数据

  • Java编程实现对象克隆(复制)代码详解

    克隆,想必大家都有耳闻,世界上第一只克隆羊多莉就是利用细胞核移植技术将哺乳动物的成年体细胞培育出新个体,甚为神奇.其实在Java中也存在克隆的概念,即实现对象的复制. 本文将尝试介绍一些关于Java中的克隆和一些深入的问题,希望可以帮助大家更好地了解克隆. 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适

  • 利用Java反射机制实现对象相同字段的复制操作

    一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档),我采用POJO来对应数据表结构,使用VO来给传递前端要展示的数据,同时使用DTO来进行请求参数的封装.以上是一个具体的场景,可以发现这样子一个现象:POJO.VO.DTO对象是同一个数据的不同视图,所以会有很多相同的字段,由于不同的地方使用不同的对象,无可避免的会存在对象之间的值迁移问题,迁移的一

  • Java基础之面向对象机制(多态、继承)底层实现

    一.Java的前世 为什么会产生Java?Java的特点是什么? 从C语言开始讲,C语言是一种结构化语言,模块化编程,便于程序的调试,依靠非常全面的运算符和多样的数据类型,可以轻易完成各种数据结构的构建,通过指针类型更可对内存直接寻址以及对硬件进行直接操作,因此既能够用于开发系统程序,也可用于开发应用软件.其缺点就是封装性弱,程序的安全性上不是很好.C语言的异常处理一般使用setjmp()与longjmp(),在捕获到异常时进行跳转:或者使用abort()和exit()两个函数,强行终止程序的运

  • Java对象的复制三种方式(小结)

    1.概述 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的.例如下面程序展示的情况: class Student { private int number; public int getNumber() { return number; } public void setNumber(int number)

  • 详解Java对象的内存布局

    前言 今天来讲些抽象的东西 -- 对象头,因为我在学习的过程中发现很多地方都关联到了对象头的知识点,例如JDK中的 synchronized锁优化 和 JVM 中对象年龄升级等等.要深入理解这些知识的原理,了解对象头的概念很有必要,而且可以为后面分享 synchronized 原理和 JVM 知识的时候做准备. 对象内存构成 Java 中通过 new 关键字创建一个类的实例对象,对象存于内存的堆中并给其分配一个内存地址,那么是否想过如下这些问题: 这个实例对象是以怎样的形态存在内存中的? 一个O

随机推荐