美文网首页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的对象的拷贝方式集合

    1. 反射 使用了缺省的方式进行copy。要求源对象和目标对象必须实现getter和setter。进行copy时,...

  • java 对象的拷贝

    拷贝:即复制 对象拷贝:即对象复制 java 对象拷贝分类:浅拷贝、深拷贝 java 对象的浅拷贝和深拷贝针对包含...

  • Java基础-集合框架

    概念 Java集合框架提供了数据持有对象的方式,提供了对数据集合的操作,Java集合框架位于java.util包下...

  • 集合框架

    java集合框架提供了数据持有对象的方式,提供了对数据集合的操作。java集合框架位于java.util包下,主要...

  • Java 之浅拷贝、深拷贝,你到底知多少?

    在 Java 开发中,对象拷贝或者说对象克隆是常有的事,对象克隆最终都离不开直接赋值、浅拷贝、深拷贝 这三种方式,...

  • 解开对copy、mutableCopy,深复制和浅复制的疑惑

    一、深拷贝,浅拷贝 二、非集合类的对象 shallow copy 和 deep copy 三、集合类的对象自身的 ...

  • Java中创建对象的方式

    一:Java中创建对象的方式 示例 注:同步更新于CreateObjectTest 二:Java的深浅拷贝 三:如...

  • Java 集合框架总结(一)

    集合概述 Java集合框架标准化了Java处理对象组的方式。Java集合框架在JDK1.2版本提出,在JDK1.5...

  • 什么是浅拷贝和深拷贝?

    创建Java对象的方式包括new、反射、反序列化、拷贝,那么什么是拷贝呢?浅拷贝和深拷贝又有什么区别呢? 什么是拷...

  • iOS 集合的深复制与浅复制

    iOS 集合的深复制与浅复制 概念 对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象本身,仅仅是...

网友评论

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

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