Javaオブジェクトの深度コピーと効率比較

23310 ワード

Javaオブジェクトの深度コピー-ツールクラス
  • 紹介
  • 上コード
  • 性能比較
  • まとめ
  • 紹介する
    ここでは,反射により深さコピーが可能なコピーオブジェクトツールクラスを独自に作成した.深度コピーの基本タイプ、Collection、Map、Array、カスタムオブジェクトをサポートします.注意事項:ソースオブジェクトとターゲットオブジェクト、フィールド名は同じでなければなりません.
    深度コピー:たとえばコピーが必要なソースオブジェクトに1つのオブジェクトが含まれています.ターゲットオブジェクトとは異なりフィールドのみです.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は比較していないので、きっとすぐにできますが、浅いコピーでもあるので、自分で比較してみてください.以下は参考にしてください.
    属性コピー方式
    10,000回
    100000回
    SpringのBeanUtils.copyProperties
    344~472ミリ秒
    455~580ミリ秒
    自分で書いた
    40~100ミリ秒
    168~235ミリ秒
    まとめ
    オブジェクトコピーは主にエンティティの変換に使用され、基本的には100000を超えることはありません.このツールクラスも基本的に十分ですが、サポートされているタイプは複雑ではありません.このバージョンはまだ完備されていないので、更新する時間があります.