一看就懂!Java利用反射实现快速Bean属性赋值(浅克隆、深克隆)

在开发中经常需要将PO、VO、DTO、DO相互转换,如果一个个set将十分麻烦,现在也有很成熟的转换工具类,例如dozer,本人日常开发也会使用这个工具。出于技痒,于是自己开始研究利用反射实现转换工具。

2020/3/10版:


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 利用反射原理的对象转换类
 */
public class BeanUtils {
    private static final String GET = "get";
    private static final String SET = "set";

    /**
     * 浅复制
     *
     * @param from 转换对象
     * @param to   目标对象
     * @param <T>  返回对象
     * @return
     */
    public static <T> T covert(T from, T to) {
        System.out.println("-----------开始转换----------");
        Class<?> fromClass = from.getClass();
        Class<?> toClass = to.getClass();
        Method[] toClassMethods = toClass.getMethods();
        //遍历to含有的方法
        for (Method method : toClassMethods) {
            String methodName = method.getName();
            // 如果该方法是set方法
            if (methodName.startsWith("set")) {
                try {
                    // 从from 获取对应的get方法
                    Method getMethod = fromClass.getDeclaredMethod(methodName.replace("set", "get"));
                    // 执行get方法获取from的值
                    Object value = getMethod.invoke(from);
                    // 执行set方法设置to的值
                    method.invoke(to, value);

                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("-----------转换完成----------");
        return to;
    }


}
    public static void main(String[] args) {

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        UserEntity userEntity = new UserEntity();
        userEntity.setId(1);
        userEntity.setName("张三");
        userEntity.setPassword("123admin");
        userEntity.setSex("男");
        userEntity.setUsername("user");
        userEntity.setList(list);
        System.out.println(userEntity);
        UserVO covert = (UserVO) BeanUtils.covert(userEntity, new UserVO());
        System.out.println(covert);

        list.add(4);
        System.out.println("------------修改原本的list后---------");
        System.out.println(covert);
    }

输出: 

这个版本是我的第一版,目前实现了属性的浅复制,可以看到例子中list如果后面修改,会影响到转换后vo的list属性,原因是只实现了浅复制。本来想利用clone克隆实现深复制的。但是发现 Object value= getMethod.invoke(from); 我想不出如何调用将value强转回原本类型,唉还是对反射机制不够了解....待了解后在进行进一步补充。但是日常开发中大多数不会出现转换之后还需要修改原本pojo属性的场景。

2020/3/25

这里采用了取巧的方式,直接将原本的对象先深克隆,就不需要一步步判断是否需要对当前值进行克隆。

深克隆的方法有两种:1.序列化与反序列化生成对象。2.所有引用类型都得实现Cloneable。

这次采用了序列化与反序列化的思路,实现了对象的深克隆。(因为序列化的话比较现实,所有的引用类型都得实现Cloneable就太麻烦了)

//实现序列化接口
public class UserEntity implements Serializable {

    private Integer id;
    private String username;
    private String password;
    private String name;
    private String sex;
    private List<Integer> list;
}
    /**
     * 深拷贝
     *
     * @param from
     * @param to
     * @param <T>
     * @return
     */
    public static <T> T depthCovert(T from, T to) {
        Class<?> fromClass = from.getClass();
        Class<?> toClass = to.getClass();

        System.out.println("-----------开始转换----------");
        System.out.println("被转换的对象类型" + fromClass);
        System.out.println("待转换的对象类型" + toClass);
        if (!(fromClass instanceof Serializable)) {
            throw new RuntimeException("转换对象没有实现Serializable");
        }


        try {
            from = deepClone(from);
        } catch (Exception e) {
            throw new RuntimeException("深拷贝对象异常");
        }


        Method[] toClassMethods = toClass.getMethods();
        //遍历to含有的方法
        for (Method method : toClassMethods) {
            String methodName = method.getName();
            // 如果该方法是set方法
            if (methodName.startsWith("set")) {
                try {
                    // 从from 获取对应的get方法
                    Method getMethod = fromClass.getDeclaredMethod(methodName.replace("set", "get"));
                    // 执行get方法获取from的值
                    Object invoke = getMethod.invoke(from);
                    // 执行set方法设置to的值
                    method.invoke(to, invoke);

                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("-----------转换完成----------");
        return to;
    }


    private static <T> T deepClone(T t) throws IOException, ClassNotFoundException {
        
        System.out.println("-----------开始克隆----------");
        
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(t);
        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        t = (T) ois.readObject();
        System.out.println("-----------结束克隆----------");
        return t;
    }

可以看到,userVO里的list和原本的list已经不是同一个List了,深拷贝成功。

发布了77 篇原创文章 · 获赞 62 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/weixin_42236404/article/details/104779025