利用反射优雅的实现两个JavaBean的合并

  1. 使用场景
  2. 代码解析

使用场景

设想我们有两个JavaBean A和B,JavaBean里面有几个成员变量,现在我们想把B对象里面的变量覆盖到A里面.同时我们需要考虑如果B里面的部分成员变量如果是空,那我们就保留A里面的对象.那么我们可以利用Java反射的特性对Class进度get,set操作.

它将支持以下特性:

1.假设有A,B两个对象,此方法会将B对象覆盖到A对象里面,如果B对象的某些成员变量为空,则保留A对象中的成员变量.如果B对象中的某些成员变量不为空,则替换A中的成员变量.

2.如果成员变量是个Object类型,我们会对Object进行递归遍历.直至它的成员变量不是Object类型.

3.如果成员变量是数组类型,我们会对数组进行逐一遍历,再根据Object的逻辑去遍历.

4.考虑到继承的特性,如果接受到的引用是个子类,我们会对它的父类进行同样的遍历方式.

代码解析

1.我们先需要一个types来区分Object类型与非Object类型
public static List<String> types = new ArrayList<String>();
    static {
        types.add("java.lang.Integer");
        types.add("java.lang.Double");
        types.add("java.lang.Float");
        types.add("java.lang.Long");
        types.add("java.lang.Short");
        types.add("java.lang.Byte");
        types.add("java.lang.Boolean");
        types.add("java.lang.Character");
        types.add("java.lang.String");
        types.add("int");
        types.add("double");
        types.add("long");
        types.add("short");
        types.add("byte");
        types.add("boolean");
        types.add("char");
        types.add("float");
    }
2.我们定义一个范型方法用来接收两个相同的JavaBean,同时返回合并好的JavaBean,下面的方法主要是判断 JavaBean是否还有父类,如果有则,对它的父类向上递归.
    /**
     * 利用反射合并两个实例类,将newProperties中的属性覆盖到preProperties,
     * 如果newProperties中的属性为空,则保留preProperties中的属性
     *
     * 已经支持递归覆盖.对成员变量是Object的成员变量进行递归
     * 如果成员变量是子类,还可以找它的父类向上覆盖
     *
     * @param preProperties 之前旧的实例属性
     * @param newProperties 新的实例属性
     * @param <T>                 返回合并后的实例属性
     * @return
     */
    public static <T> T mergeDeviceProperties(T preDeviceProperties, T newDeviceProperties) throws IllegalAccessException {
        if (preDeviceProperties == null) {
            preDeviceProperties = newDeviceProperties;
            return preDeviceProperties;
        }
        Class tClass = newDeviceProperties.getClass();
        while (tClass != null) {
            merge(preDeviceProperties, tClass.cast(newDeviceProperties));
            tClass = tClass.getSuperclass();
        }
        return preDeviceProperties;
    }
2.这是我们最核心的方法,主要操作就是对B里面的成员变量覆写到A中,同时我们需要判断成员变量是否是基本数据类型和包装类型,以及它是否是一个数组.
    private static <T> T merge(T preDeviceProperties, T newDeviceProperties) throws IllegalAccessException {
        Field[] preFileds = preDeviceProperties.getClass().getDeclaredFields();
        Field[] newFileds = newDeviceProperties.getClass().getDeclaredFields();

        for (int i = 0; i < preFileds.length; i++) {
            Field preField = preFileds[i];
            Field newField = preFileds[i];
            if (Modifier.isStatic(newField.getModifiers())) {
                continue;
            }
            Field targetField = newFileds[i];
            if (Modifier.isStatic(targetField.getModifiers())) {
                continue;
            }

            preField.setAccessible(true);
            newField.setAccessible(true);

            if(null != newField.get(newDeviceProperties)){
                //如果成员变量是个数组,那么遍历数组的每个对象并进行递归合并
                if(preField.getType().isArray()){
                    int length = Array.getLength(preField.get(preDeviceProperties));
                    for(int j=0;j<length;j++){
                        Object preDeProperty = Array.get(preField.get(preDeviceProperties),j);
                        Object newDeProperty = Array.get(newField.get(newDeviceProperties),j);
                        mergeDeviceProperties(preDeProperty,newDeProperty);
                    }
                }
                //如果成员变量不是基本数据类型或者包装类型,则进行递归遍历
                else if (!types.contains(preField.getType().getName())) {
                    mergeDeviceProperties(preField.get(preDeviceProperties), newField.get(newDeviceProperties));
                } else {
                    preField.set(preDeviceProperties, newField.get(newDeviceProperties));
                }
            }
        }
        return preDeviceProperties;
    }

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值