Java对象拷贝原理剖析及最佳实践


1序言

目标复制,是在研发流程中,避不开的一个过程,既存在Po、Dto、Do、Vo每个表现层数据库的变换,也存在系统交互如实例化、反序列化。

Java对象复制分成深拷贝和浅拷贝,现阶段常见的特性复制专用工具,包含Apache的BeanUtils、Spring的BeanUtils、Cglib的BeanCopier、mapstruct全是浅拷贝。

1.1深拷贝

深拷贝:对基本数据类型开展值传递,对引用数据类型,建立一个新的目标,并拷贝内容称之为深拷贝。

深拷贝普遍有如下四种控制方式:

对象

Serializable实例化

完成Cloneable接口

JSON实例化

1.2浅拷贝

浅拷贝:对基本数据类型开展值传递,对引用数据类型开展引用传递一样的复制称之为浅拷贝。根据完成Cloneabe接口并重新写过Object类中的clone()方式能够实现浅复制。

2常见目标复制专用工具基本原理分析及性能对比

现阶段常见的特性复制专用工具,包含Apache的BeanUtils、Spring的BeanUtils、Cglib的BeanCopier、mapstruct。

ApacheBeanUtils:BeanUtils是Apachecommons部件里边中的一员,由Apache给予的一套开源系统api,用以简单化对javaBean操作,可以对基本类型全自动变换。

SpringBeanUtils:BeanUtils是spring框架下带有的专用工具,在org.springframework.beans包下,spring新项目能够直接用。

CglibBeanCopier:cglib(CodeGenerationLibrary)是一个强悍的、性能卓越、高质量代码生成类库,BeanCopier依托cglib的字节码增强能力,动态生成实现类,进行对象复制。

mapstruct:mapstruct是一个Java注解Cpu,用以形成类型安全的Bean投射类,在建立时,依据注释形成实现类,进行目标复制。

2.1基本原理剖析

2.1.1ApacheBeanUtils

使用方法:BeanUtils.copyProperties(target,source);

BeanUtils.copyProperties目标复制的关键编码如下所示:

//1.获得源对象的属性叙述

PropertyDescriptor[]origDescriptors=this.getPropertyUtils().getPropertyDescriptors(orig);

PropertyDescriptor[]temp=origDescriptors;

intlength=origDescriptors.length;

Stringname;

Objectvalue;

//2.循环系统获得源目标每一个特性,设定目标对象基础属性

for(inti=0;iPropertyDescriptororigDescriptor=temp[i];

name=origDescriptor.getName();

//3.校检源目标字段名能读切目标对象该字段名应写

if(!"class".equals(name)&&this.getPropertyUtils().isReadable(orig,name)&&this.getPropertyUtils().isWriteable(dest,name)){

try{

//4.获得源目标字段值

value=this.getPropertyUtils().getSimpleProperty(orig,name);

//5.复制特性

this.copyProperty(dest,name,value);

}catch(NoSuchMethodExceptionvar10){

}

}

}

循环遍历源对象每一个特性,对于每一个特性,复制步骤为:

校检由来类字段名是否可以读isReadable

校检总体目标类字段名是否可以写isWriteable

获得由来类字段名基础属性getSimpleProperty

获得总体目标类字段种类type,然后进行数据转换

设定总体目标类字段值

因为一个字段复制时每一个阶段都是会启用PropertyUtilsBean.getPropertyDescriptor获得特性配备,而此方法根据for循环获得类字段名特性,严重危害复制高效率。

获得字段名特性配备的关键编码如下所示:

PropertyDescriptor[]descriptors=this.getPropertyDescriptors(bean);

if(descriptors!=null){

for(inti=0;iif(name.equals(descriptors[i].getName())){

returndescriptors[i];

}

}

}

2.1.2SpringBeanUtils

使用方法:BeanUtils.copyProperties(source,target);

BeanUtils.copyProperties关键编码如下所示:

PropertyDescriptor[]targetPds=getPropertyDescriptors(actualEditable);

ListignoreList=ignoreProperties!=null?Arrays.asList(ignoreProperties):null;

PropertyDescriptor[]arr$=targetPds;

intlen$=targetPds.length;

for(inti$=0;i$PropertyDescriptortargetPd=arr$[i$];

MethodwriteMethod=targetPd.getWriteMethod();

if(writeMethod!=null&&(ignoreList==null||!ignoreList.contains(targetPd.getName()))){

PropertyDescriptorsourcePd=getPropertyDescriptor(source.getClass(),targetPd.getName());

if(sourcePd!=null){

MethodreadMethod=sourcePd.getReadMethod();

if(readMethod!=null&&ClassUtils.isAssignable(writeMethod.getParameterTypes()[0],readMethod.getReturnType())){

try{

if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())){

readMethod.setAccessible(true);

}

Objectvalue=readMethod.invoke(source);

if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())){

writeMethod.setAccessible(true);

}

writeMethod.invoke(target,value);

}catch(Throwablevar15){

thrownewFatalBeanException("Couldnotcopyproperty'"+targetPd.getName()+"'fromsourcetotarget",var15);

}

}

}

}

}

本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;

2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;

3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;

4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;

5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/293444.html

(0)
上一篇 2022年11月24日
下一篇 2022年11月24日

相关推荐

发表回复

登录后才能评论