Java 开发中的对象拷贝
前言
在 Java 开发中,很多时候需要将两个属性基本相同的对象进行属性复制,比如 DO 转 VO等等。
本文主要介绍自己实现的简易拷贝工具类与 Spring 提供的属性拷贝的对比。
Spring 提供的属性拷贝
在 Spring 中直接调用 BeanUtils.copyProperties();即可。
它的核心通过循环 target 的所有方法名,然后在 source 中找到对应的方法名,最后通过反射从 source 中获取并写入 target 中。
Spring 没有通过 java.lang.reflect 中的 Field 来做,而是通过 java.beans 中的 PropertyDescriptor 来实现。
补充:PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
通过 PropertyDescriptor 提供的 getReadMethod() 和 getWriteMethod() 方法,可以方便的获取到读取、写入属性值的方法(Method)。
同时,Spring 也做了缓存,在测试中,第一次的对象拷贝用时 300+ 毫秒,之后在缓存中获取,用时 0 毫秒。
源码如下图所示:


缓存源码:

自己写的简易版
public static void copyBean(Object target, Object source) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class targetClass = target.getClass();
Class sourceClass = source.getClass();
// 获取目标类的所有参数 Field
Field[] fields = targetClass.getDeclaredFields();
// 为目标类的每个参数设值
for (Field field : fields) {
// 如果数据源对象中存在对应的参数
Field sourceField = sourceClass.getDeclaredField(field.getName());
if (null != sourceField) {
Field targetField = targetClass.getDeclaredField(field.getName());
targetField.setAccessible(true);
sourceField.setAccessible(true);
targetField.set(target, sourceField.get(source));
}
}
}
// 类似 Spring 的版本
public static void copyBeanByMethod(Object target, Object source) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
Class targetClass = target.getClass();
Class sourceClass = source.getClass();
Field[] sourceFields = sourceClass.getDeclaredFields();
for (Field field : sourceFields) {
PropertyDescriptor targetProperty;
try {
targetProperty = new PropertyDescriptor(field.getName(), targetClass);
} catch (IntrospectionException e) {
continue;
}
Method writeMethod = targetProperty.getWriteMethod();
if (writeMethod != null) {
PropertyDescriptor sourceProperty = new PropertyDescriptor(field.getName(), sourceClass);
Method readMethod = sourceProperty.getReadMethod();
if (!Modifier.isPublic(readMethod.getModifiers())) {
readMethod.setAccessible(true);
}
// 读取 source 中属性的值
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getModifiers())) {
writeMethod.setAccessible(true);
}
// 为 target 对应的属性赋值
writeMethod.invoke(target, value);
}
}
}
小结
Spring 所提供的属性拷贝虽然第一次效率较低,但随后如果再次使用相同的 source 进行拷贝,则 Spring 会通过第一次拷贝保存的缓存来直接进行快速的拷贝
参考资料
[1] 谈谈 Java 开发中的对象拷贝
Java 开发中的对象拷贝的更多相关文章
- 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)
编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...
- Java开发中文件读取方式总结
JAVA开发中,免不了要读文件操作,读取文件,首先就需要获取文件的路径. 路径分为绝对路径和相对路径. 在文件系统中,绝对路径都是以盘符开始的,例如C:\abc\1.txt. 什么是相对路径呢?相对路 ...
- Java开发中常见的危险信号(上)
本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...
- [ 转载 ] Java开发中的23种设计模式详解(转)
Java开发中的23种设计模式详解(转) 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...
- Java开发中代码规范有哪些?
Java开发中所要遵守的编码规范大体上有如下7点.命名规范.注释规范.缩进排版规范.文件名规范.声明规范.语句规范以及编程规范. 1.命名规范 (1)所有的标示符都只能用ASCⅡ字母(A-Z或a-z) ...
- EBS OAF开发中实体对象和视图对象的属性设置器
EBS OAF开发中实体对象和视图对象的属性设置器 (版权声明.本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) 源文: Home > Oracle ...
- Java开发中常用jar包整理及使用
本文整理了我自己在Java开发中常用的jar包以及常用的API记录. <!-- https://mvnrepository.com/artifact/org.apache.commons/com ...
- Java开发中RMI和webservice区别和应用领域
Java开发中RMI和webservice区别和应用领域 一.RMI和webservice区别和联系 0. 首先,都是远程调用技术. 1. RMI是在TCP协议上传递可序列化的java对象(使用Str ...
- JAVA开发中相对路径,绝对路径全面总结
JAVA开发中相对路径,绝对路径全面总结 博客分类: Java综合 JavaJSP应用服务器Servlet网络应用 1.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径, ...
随机推荐
- JavaScript日历控件开发 C# 读取 appconfig文件配置数据库连接字符串,和配置文件 List<T>.ForEach 调用异步方法的意外 ef 增加或者更新的习惯思维 asp.net core导入excel 一个二级联动
JavaScript日历控件开发 概述 在开篇之前,先附上日历的代码地址和演示地址,代码是本文要分析的代码,演示效果是本文要实现的效果代码地址:https://github.com/aspwebc ...
- 启动mysql报错 -- ERROR! The server quit without updating PID file
开发说某个测试环境的mysql,无法重启了,报以下错误提示: # service mysqld restart Shutting down MySQL.. SUCCESS! Starting MySQ ...
- appium简明教程(11)——使用resource id定位(仅支持安卓4.3以上系统)
上一节乙醇带大家了解了appium的定位策略.实际上appium的控件定位方式是完全遵守webdriver的mobile扩展协议的. 这一节将分享一下如何使用resource id来定位android ...
- cassandra运行出现了Unable to gossip with any seeds,cqlsh链接不上,提示connection refused处理办法
cassandra运行出现了Unable to gossip with any seeds,cqlsh链接不上,提示connection refused处理办法 问题描述 当启动了cassandra之 ...
- SharePoint 2013 Disaster Recovery——迁移内容数据库
安装和配置SharePoint Farm时,一定要注意将内容数据库不要放在C盘,除非你的C盘能足够承受起日益增长的数据.由于在安装SQL SERVER中没有注意,我将数据库存放在默认的 C:\Prog ...
- python字符串格式化之学习笔记
在python中格式化输出字符串使用的是%运算符,通用的形式为 •格式标记字符串 % 要输出的值组其中,左边部分的”格式标记字符串“可以完全和c中的一致.右边的'值组'如果有两个及以上的值则需要用小括 ...
- nginx last 和break redirect 和 permanent
一.last & break (1)last 和 break 当出现在location 之外时,两者的作用是一致的没有任何差异. 注意一点就是,他们会跳过所有的在他们之后的rewrite 模块 ...
- springBoot bean注入
1.@Component:把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/> 2.@Autow ...
- iOS 在object-c 中调用c文件 方法
1,新建c 头文件 lib.h 定义 c 函数 2,新建 c 实现文件,新建模板选中 c File lib.c 3,oc 中调用,引用 c 头文件 lib.h ok .搞定
- 基于Xilinx Zynq Z7045 SoC的CNN的视觉识别应用
基于Xilinx Zynq Z7045 SoC的CNN的视觉识别应用 由 judyzhong 于 星期三, 08/16/2017 - 14:56 发表 作者:stark 近些年来随着科学技术的不断进步 ...