Java 對象深度拷貝及效率比較

Java 對象深度拷貝-工具類

介紹

這裏自己寫了一個拷貝對象工具類,通過反射實現,能做到深度拷貝
支持深度拷貝 基本類型, Collection, Map, Array, 自定義對象
注意事項:源對象和目標對象,字段名稱必須一樣

深度拷貝:比如需要拷貝的源對象裏面包含一個對象,與目標對象不同只有字段一樣,BeanUtils.copyProperties 拷貝是達不到我們想要效果的(數據好像是過來了,但是對象沒變,大家可以自己試試),獲取對象的時候會報錯(原因是數據類型不匹配)

對象拷貝目前我們常用的有如下幾種

  1. spring的BeanUtils.copyProperties;
  2. 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,這個工具類也基本夠用,不過支持的類型不能太複雜,這個版本還有待完善,有時間再更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章