将一个对象同名、同类型属性拷贝到另一个对象,包括 List 集合属性

该工具类中包括了怎么从泛型类型中通过反射获取泛型类型。

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ComUtil class
 *
 * @author xxxxx
 * @date 2020.03.10 22:38
 */
public class ComUtil {

    /**
     * 用于将一个类中具有相同属性名和类型的值拷贝到另一个类中
     *
     * @param source 被复制属性的类
     * @param target 需要获取属性的类
     * @throws Exception
     */
    public static void copyProperties(Object source, Object target) throws Exception {
        if (source == null || target == null) {
            throw new Exception("传入的 source 或 target 中有为 null 的对象");
        }
        // 获取 source 和 target 的属性列表
        Field[] sourFields = source.getClass().getDeclaredFields();
        Field[] tarFields = target.getClass().getDeclaredFields();

        // 将 source 的属性对象为 value,属性名为 key 封装为 map
        Map<String, Field> sourFieldMap = new HashMap<>(16);
        for (Field sourField : sourFields) {
            // 获取属性名
            String fieldName = sourField.getName();
            sourFieldMap.put(fieldName, sourField);
        }

        for (Field tarField : tarFields) {
            // 获取属性名
            String fieldName = tarField.getName();
            // 从 sourFieldMap 中通过 fieldName 取值,若能取出表示存在相同的属性名
            Field sourField = sourFieldMap.get(fieldName);
            if (sourField != null) {
                // 获取 List 泛型类型
                Class tarGenericClass = getGenericClass(tarField);
                Class sourGenericClass = getGenericClass(sourField);

                // 获取属性声明的类型 Class 对象
                Class<?> sourType = sourField.getType();
                Class<?> tarType = tarField.getType();

                // 获取权限
                sourField.setAccessible(true);
                tarField.setAccessible(true);

                // 若不是 List 或其父接口类型,为 null
                if (tarGenericClass == null && sourGenericClass == null) {
                    // target 属性类型是 source 属性类型的子类或子接口
                    if (sourType.isAssignableFrom(tarType)) {
                        tarField.set(target, sourField.get(source));
                    }
                } else if (tarGenericClass != null && sourGenericClass != null) {
                    // Iterable 是 List 最顶层接口,在 sourGenericClass 中判断是声明类型是 List 或其父接口
                    Iterable sourList = (Iterable) sourField.get(source);
                    if (sourList == null) {
                        continue;
                    }
                    // 该集合用于添加 target 拷贝的对象
                    List tarList = new ArrayList();
                    // 遍历 sourList,取出每个泛型对象
                    for (Object sourObj : sourList) {
                        // 创建 target List 集合泛型实例
                        Object tarObj = tarGenericClass.newInstance();
                        // 递归调用本方法,将相同属性名赋值
                        copyProperties(sourObj, tarObj);
                        // 将实例对象添加到集合中
                        tarList.add(tarObj);
                    }
                    // 将集合赋值给 target 同名的属性
                    tarField.set(target, tarList);
                }
            }
        }

    }

    /**
     * 获取属性类型中的泛型类型,获取泛型的过程适用于其他类型,但是本方法仅适用于 List 集合,
     * 并且只有一个泛型的情况,若有需求后续增加功能。
     *
     * @param field
     * @return
     * @throws Exception
     */
    private static Class getGenericClass(Field field) throws Exception {
        // 获取属性声明的类型 Class 对象
        Class<?> type = field.getType();
        // 判断该 type 是否是 List 或其父接口
        if (type.isAssignableFrom(List.class)) {

            // 获取该属性声明的类型(Type 接口),getType():是获取属性声明的类型 Class 对象
            Type genericType = field.getGenericType();
            if (genericType == null) {
                return null;
            }
            // 判断 geneicType 是否是参数化类型,即明确指定泛型的类型,如:java.util.List<java.lang.String>
            if (genericType instanceof ParameterizedType) {

                //因为 genericType 是 ParameterizedType 的实例,故可以强转
                ParameterizedType pt = (ParameterizedType) genericType;

                // 获取泛型的类型数组
                Type[] genericArgs = pt.getActualTypeArguments();

                // 当泛型类型大于 1 个时,抛出异常
                if (genericArgs.length > 1) {
                    throw new Exception(genericType + "  " + field.getName() + ": 泛型不只一个无法赋值");
                }

                // 当只有一个泛型类型时,获取泛型类型
                return (Class) genericArgs[0];
            }
        }
        return null;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值