介紹
這裏自己寫了一個拷貝對象工具類,通過反射實現,能做到深度拷貝。
支持深度拷貝 基本類型, 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,這個工具類也基本夠用,不過支持的類型不能太複雜,這個版本還有待完善,有時間再更新。