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.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径, ...
随机推荐
- 反射已经"Out",动态编译才能"Hold"住
Net支持反射功能以后,确实使我们Net程序眼前一亮啊,真是太神奇了,只需要传入字符串就可以完成功能.可以说,反射功能的引入,使我们在处理某些问题上更加得心应手. 传统的Db管理软件中,数据库字段的频 ...
- ElementUI 按需引入坑爹的点记录
官网说的是这样的: 但实际上,应该是这样修改: { "presets": [ ["env", { "targets": { "br ...
- mysqlslap 压力测试工具
[背景] 由于一些不可描述的原因,我要确定一条业务SQL在给定的MySQL环境下的执行效率:比如说200个session同时跑同样一条SQL 我们数据库的吞吐量怎么样? 刚收到这个需求的时候,感觉这个 ...
- Zephir入门 —— 语法篇
概述 Zephir的语法跟PHP很相似,所以这里不会把官网的文档照搬过来翻译一遍,而是会把一些Zephir相较于PHP比较特别的语法挑出来讲一下.如果想要要完整学习Zephir的语法,没有比官网的文档 ...
- kibana显示报错
"status": 500, "reason": "ElasticsearchException[org.elasticsear ...
- LED音乐频谱之输入数据处理
转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38023431 通过前面的介绍我们知道.声音信号要通过AD转换,变成我们可以处理 ...
- PHP+FastCGI+Nginx配置PHP运行环境方法
PHP+FastCGI+Nginx配置PHP运行环境 Nginx不支持对外部程序的调用,所以必须通过FastCGI接口实现对外部程序的调用从而实现对客户端动态页面请求的处理. CGI的英文全称为Com ...
- 深入理解Java中的逃逸分析
在Java的编译体系中,一个Java的源代码文件变成计算机可执行的机器指令的过程中,需要经过两段编译,第一段是把.java文件转换成.class文件.第二段编译是把.class转换成机器指令的过程. ...
- Delphi对象池MyObjectPool.pas
对象池一般在服务端使用,所以稳定性是第一的. 欢迎提意见 unit uMyObjectPool; interface uses SyncObjs, Classes, Windows, SysUtils ...
- MSSQL 的Top 和 MAX 效率测试
环境: MSSQL 2008, 都在没有使用缓存的情况下面执行 表中有8W 条记录 分类1有134条记录 分别测试了3个语句 -- A select 字段1 from 表1 WHERE Ftype=' ...