介绍
这里自己写了一个拷贝对象工具类,通过反射实现,能做到深度拷贝。
支持深度拷贝 基本类型, Collection, Map, Array, 自定义对象。
注意事项:源对象和目标对象,字段名称必须一样
深度拷贝:比如需要拷贝的源对象里面包含一个对象,与目标对象不同只有字段一样,BeanUtils.copyProperties 拷贝是达不到我们想要效果的(数据好像是过来了,但是对象没变,大家可以自己试试),获取对象的时候会报错(原因是数据类型不匹配)
对象拷贝目前我们常用的有如下几种
- spring的BeanUtils.copyProperties;
- cglib的BeanCopier;
上代码
// 拷贝对象
public class ObjectCopyUtil {
/**
* 反射 深copy
* 支持类型:基本类型, Collection, Map, Array, 自定义对象
* 注意:Collection里面不能嵌套Collection
* @param source 源
* @param target 目标
* @return target
* @throws Exception
*/
public static Object deepCopy(Object source,Object target) throws Exception{
if(null == source){
return null;
}
//源数据
Class<?> sourceClassType = source.getClass();
//复制目标数据
Class<?> targetClassType = target.getClass();
//源数据Map
Map<String,Object> sourceMap = new HashMap<>(sourceClassType.getDeclaredFields().length);
//获取源数据
for(Field field : sourceClassType.getDeclaredFields()){
field.setAccessible(true);
Object value = field.get(source);
if(value != null){
sourceMap.put(field.getName(),value);
}
}
//赋值目标数据
for(Field field : targetClassType.getDeclaredFields()){
field.setAccessible(true);
Object targetValue;
Object value = sourceMap.get(field.getName());
if(value == null){
continue;
}
if(value instanceof Collection<?>){
//获取数组里面的泛型
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
Class<?> actualTypeArgument = (Class<?>)parameterizedType.getActualTypeArguments()[0];
//获取源Collection
Collection list = (Collection)value;
//创建Collection
Collection targetList = CollectionFactory.createCollection(field.getType(),list.size());
Iterator iterator = list.iterator();
while (iterator.hasNext()){
Object targetItem;
Object item = iterator.next();
if(isBaseType(item)){
//基础类型
targetItem = item;
}else if(item instanceof Map){
//map
targetItem = item;
}else if(item.getClass().isArray()){
//数组
targetItem = item;
}else if(item instanceof Collection<?>){
//Collection 不支持
//throw new IllegalArgumentException("Collection cannot be nested within collection");
targetItem = null;
}else{
targetItem = deepCopy(item,actualTypeArgument.newInstance());
}
targetList.add(targetItem);
}
targetValue = targetList;
}else if(value instanceof Map){
//map
targetValue = value;
}else if(value.getClass().isArray()){
//数组
targetValue = value;
}else if(isBaseType(value)){
//基础类型
targetValue = value;
}else{
//自定义对象
targetValue = deepCopy(value,field.getType().newInstance());
}
field.set(target,targetValue);
}
return target;
}
public static boolean isBaseType(Object object){
if(object.getClass().isPrimitive()){
return true;
}else if(object instanceof String){
return true;
}else if(object instanceof Integer){
return true;
}else if(object instanceof Double){
return true;
}else if(object instanceof Float){
return true;
}else if(object instanceof Long){
return true;
}else if(object instanceof Boolean){
return true;
}else if(object instanceof Date){
return true;
}else if(object instanceof Byte){
return true;
}else if(object instanceof Short){
return true;
}else {
return false;
}
}
}
性能比较
cglib的BeanCopier没有比较了,肯定会很快,但是也是浅拷贝
大家可以自己比较一下,如下仅当参考:
属性拷贝方式 | 10000次 | 100000次 |
---|---|---|
spring的BeanUtils.copyProperties | 344~472 毫秒 | 455~580 毫秒 |
自己写的 | 40~100 毫秒 | 168~235 毫秒 |
总结
对象拷贝主要用在实体的转换上,基本上数据也不会超过100000,这个工具类也基本够用,不过支持的类型不能太复杂,这个版本还有待完善,有时间再更新。