美文网首页jdk
Java的对象的拷贝方式集合

Java的对象的拷贝方式集合

作者: 小胖学编程 | 来源:发表于2020-11-16 15:15 被阅读0次

    1. 反射

    使用了缺省的方式进行copy。要求源对象和目标对象必须实现getter和setter。进行copy时,内部会缓存缺省对象,以优化性能。

    源码位置:org.springframework.beans.BeanUtils

    public class TestJavaUtils {
    
        public static void main(String[] args) {
            UserPo userPo=new UserPo();
            userPo.setId(1001L);
            userPo.setName("tom");
            userPo.setAge(12);
    
            UserDto userDto=new UserDto();
            //源对象:目标对象
            BeanUtils.copyProperties(userPo,userDto);
            System.out.println(userDto);
        }
    
    
        @Data
        public static class UserDto{
            private Long id;
    
            private String name;
    
            private Integer age;
    
            private String sex;
        }
        @Data
        public static class UserPo{
            private Long id;
    
            private String name;
    
            private Integer age;
        }
    }
    

    2. cglib字节码

    copy对象时,可以使用CGLib的BeanCopier(其原理是运行时动态生成了用于复制某个类的字节码),其性能比反射框架org.springframework.beans.BeanUtils性能要高。

    /**
     * @param source      原始对象
     * @param targetClass 拷贝的对象类型
     */
    public static < T1,T2 > T2 createCopy(T1 source, Class < T2 > targetClass) {
        if (source == null) {
            throw new RuntimeException("参数异常");
        } else {
            T2 target;
            try {
                target = targetClass.newInstance();
            } catch(Exception e) {
                throw new RuntimeException(e);
            }
            BeanCopier beanCopier = BeanCopier.create(source.getClass(), targetClass, false);
            beanCopier.copy(source, target, null);
            return target;
        }
    }
    

    缓存优化版

        private static Map<String, BeanCopier> beanCopierMap = new ConcurrentHashMap();
    
        /**
         * 拷贝对象.
         * 只能拷贝  字段名&类型&getter类型完全一致的属性。
         * 但是Long->long int->long 是无法拷贝的。
         * <p>
         * 效率:该方法的效率是 Spring.BeanUtil.copy的100倍以上。基本和系统的set是等效率的,某些场景下甚至比set还快
         *
         * @param dest 目标对象
         * @param source 源对象
         */
        public static void copyBean(Object dest, Object source) {
            //缓存的key
            String key = generateKey(source.getClass(), dest.getClass());
            try {
    
                BeanCopier beanCopier = beanCopierMap.get(key);
                //此处可以避免computeIfAbsent性能问题。
                if (beanCopier == null) {
                    beanCopier = beanCopierMap.computeIfAbsent(key,
                            k -> BeanCopier.create(source.getClass(), dest.getClass(), false));
                }
                beanCopier.copy(source, dest, null);
            } catch (Throwable e) {
                log.error("", e);
            }
        }
    

    3. get和set的链式拷贝

    本质是使用getter和setter的方式进行copy,但是借助了jdk8的链式编程。

    org.springframework.amqp.utils.JavaUtils源码位置(未引入rabbitMq可以粘贴代码到项目里面):

    源码中使用如下方式进行copy的。

    public final class JavaUtils {
    
        /**
         * The singleton instance of this utility class.
         */
        public static final JavaUtils INSTANCE = new JavaUtils();
    
        private JavaUtils() {
            super();
        }
    
        /**
         * Invoke {@link Consumer#accept(Object)} with the value if the condition is true.
         * @param condition the condition.
         * @param value the value.
         * @param consumer the consumer.
         * @param <T> the value type.
         * @return this.
         */
        public <T> JavaUtils acceptIfCondition(boolean condition, T value, Consumer<T> consumer) {
            if (condition) {
                consumer.accept(value);
            }
            return this;
        }
    
        /**
         * Invoke {@link Consumer#accept(Object)} with the value if it is not null.
         * @param value the value.
         * @param consumer the consumer.
         * @param <T> the value type.
         * @return this.
         */
        public <T> JavaUtils acceptIfNotNull(T value, Consumer<T> consumer) {
            if (value != null) {
                consumer.accept(value);
            }
            return this;
        }
    
        /**
         * Invoke {@link Consumer#accept(Object)} with the value if it is not null or empty.
         * @param value the value.
         * @param consumer the consumer.
         * @return this.
         */
        public JavaUtils acceptIfHasText(String value, Consumer<String> consumer) {
            if (StringUtils.hasText(value)) {
                consumer.accept(value);
            }
            return this;
        }
    
        /**
         * Invoke {@link BiConsumer#accept(Object, Object)} with the arguments if the
         * condition is true.
         * @param condition the condition.
         * @param t1 the first consumer argument
         * @param t2 the second consumer argument
         * @param consumer the consumer.
         * @param <T1> the first argument type.
         * @param <T2> the second argument type.
         * @return this.
         */
        public <T1, T2> JavaUtils acceptIfCondition(boolean condition, T1 t1, T2 t2, BiConsumer<T1, T2> consumer) {
            if (condition) {
                consumer.accept(t1, t2);
            }
            return this;
        }
    
        /**
         * Invoke {@link BiConsumer#accept(Object, Object)} with the arguments if the t2
         * argument is not null.
         * @param t1 the first argument
         * @param t2 the second consumer argument
         * @param consumer the consumer.
         * @param <T1> the first argument type.
         * @param <T2> the second argument type.
         * @return this.
         */
        public <T1, T2> JavaUtils acceptIfNotNull(T1 t1, T2 t2, BiConsumer<T1, T2> consumer) {
            if (t2 != null) {
                consumer.accept(t1, t2);
            }
            return this;
        }
    
        /**
         * Invoke {@link BiConsumer#accept(Object, Object)} with the arguments if the value
         * argument is not null or empty.
         * @param t1 the first consumer argument.
         * @param value the second consumer argument
         * @param <T> the first argument type.
         * @param consumer the consumer.
         * @return this.
         */
        public <T> JavaUtils acceptIfHasText(T t1, String value, BiConsumer<T, String> consumer) {
            if (StringUtils.hasText(value)) {
                consumer.accept(t1, value);
            }
            return this;
        }
    
    }
    

    测试用例:

    public class TestJavaUtils {
    
        /**
         * 对象的copy链式。
         */
        public static void main(String[] args) {
            UserPo userPo=new UserPo();
            userPo.setId(1001L);
            userPo.setName("tom");
            userPo.setAge(12);
    
            UserDto userDto=new UserDto();
    
            JavaUtils.INSTANCE.acceptIfNotNull(userPo.getAge(),userDto::setAge).acceptIfNotNull(userPo.getName(),userDto::setName);
    
            System.out.println(userDto);
        }
    
    
        @Data
        public static class UserDto{
            private Long id;
    
            private String name;
    
            private Integer age;
    
            private String sex;
        }
        @Data
        public static class UserPo{
            private Long id;
    
            private String name;
    
            private Integer age;
        }
    }
    

    相关文章

      网友评论

        本文标题:Java的对象的拷贝方式集合

        本文链接:https://www.haomeiwen.com/subject/qjvabktx.html