zoukankan      html  css  js  c++  java
  • Java 开发中的对象拷贝

    前言

    在 Java 开发中,很多时候需要将两个属性基本相同的对象进行属性复制,比如 DO 转 VO等等。

    本文主要介绍自己实现的简易拷贝工具类与 Spring 提供的属性拷贝的对比。

    Spring 提供的属性拷贝

    在 Spring 中直接调用 BeanUtils.copyProperties();即可。

    它的核心通过循环 target 的所有方法名,然后在 source 中找到对应的方法名,最后通过反射从 source 中获取并写入 target 中。

    Spring 没有通过 java.lang.reflect 中的 Field 来做,而是通过 java.beans 中的 PropertyDescriptor 来实现。

      补充:PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。

    通过 PropertyDescriptor 提供的 getReadMethod() 和 getWriteMethod() 方法,可以方便的获取到读取、写入属性值的方法(Method)。

    同时,Spring 也做了缓存,在测试中,第一次的对象拷贝用时 300+ 毫秒,之后在缓存中获取,用时 0 毫秒。

    源码如下图所示:

    缓存源码:

    自己写的简易版

     1 public static void copyBean(Object target, Object source) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
     2         Class targetClass = target.getClass();
     3         Class sourceClass = source.getClass();
     4         // 获取目标类的所有参数 Field
     5         Field[] fields = targetClass.getDeclaredFields();
     6         // 为目标类的每个参数设值
     7         for (Field field : fields) {
     8             // 如果数据源对象中存在对应的参数
     9             Field sourceField = sourceClass.getDeclaredField(field.getName());
    10             if (null != sourceField) {
    11                 Field targetField = targetClass.getDeclaredField(field.getName());
    12                 targetField.setAccessible(true);
    13                 sourceField.setAccessible(true);
    14                 targetField.set(target, sourceField.get(source));
    15             }
    16         }
    17     }
    18 
    19     // 类似 Spring 的版本
    20     public static void copyBeanByMethod(Object target, Object source) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
    21         Class targetClass = target.getClass();
    22         Class sourceClass = source.getClass();
    23         Field[] sourceFields = sourceClass.getDeclaredFields();
    24         for (Field field : sourceFields) {
    25             PropertyDescriptor targetProperty;
    26             try {
    27                 targetProperty = new PropertyDescriptor(field.getName(), targetClass);
    28             } catch (IntrospectionException e) {
    29                 continue;
    30             }
    31             Method writeMethod = targetProperty.getWriteMethod();
    32             if (writeMethod != null) {
    33                 PropertyDescriptor sourceProperty = new PropertyDescriptor(field.getName(), sourceClass);
    34                 Method readMethod = sourceProperty.getReadMethod();
    35                 if (!Modifier.isPublic(readMethod.getModifiers())) {
    36                     readMethod.setAccessible(true);
    37                 }
    38                 // 读取 source 中属性的值
    39                 Object value = readMethod.invoke(source);
    40                 if (!Modifier.isPublic(writeMethod.getModifiers())) {
    41                     writeMethod.setAccessible(true);
    42                 }
    43                 // 为 target 对应的属性赋值
    44                 writeMethod.invoke(target, value);
    45             }
    46         }
    47     }

    小结

    Spring 所提供的属性拷贝虽然第一次效率较低,但随后如果再次使用相同的 source 进行拷贝,则 Spring 会通过第一次拷贝保存的缓存来直接进行快速的拷贝

    参考资料

    [1] 谈谈 Java 开发中的对象拷贝

  • 相关阅读:
    JVM类加载的过程
    接口文档设计
    代码规范及CodeReview要点
    Linux权限
    Linux文件
    UltraEdit编辑器基础技巧
    Android环境配置
    JDK 环境配置
    xml没有提示解决办法<eclipse>
    mysql事务实例
  • 原文地址:https://www.cnblogs.com/zhengbin/p/7401745.html
Copyright © 2011-2022 走看看