对于两个实体类属性值的合并,java实现

由于这篇文章的浏览量更多, 一直也没来及更新,6年前写的文章。内容也一直没升级更新。

对象拷贝,在实际的业务场景中非常场景,刚好今天有时间,也来更新下这篇文章的内容。

主要分为两部分:第三方组件实现 + 反射的方式

 

1、第三方组件 reflectasm实现(强烈推荐)

POM 依赖:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>reflectasm</artifactId>
    <version>1.11.3</version>
</dependency>

废话不多说,直接上代码  BeanCopyUtil.class

import com.esotericsoftware.reflectasm.MethodAccess;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public class BeanCopyUtil {

    /**
     * 方法缓存
     */
    private static Map<Class, MethodAccess> methodMap = new ConcurrentHashMap<>();

    /**
     * 方法 index 缓存
     */
    private static Map<String, Integer> methodIndexMap = new ConcurrentHashMap<>();

    /**
     * 字段缓存
     */
    private static Map<Class, List<String>> fieldMap = new ConcurrentHashMap<>();

    /**
     * 拷贝对象
     *
     * @param source
     * @param target
     */
    public static void copyProperties(Object source, Object target) {
        copyProperties(source, target, true);
    }

    public static void copyProperties(Object source, Object target, boolean ignoreNull) {
        MethodAccess targetMethodAccess = methodMap.get(target.getClass());
        if (targetMethodAccess == null) {
            targetMethodAccess = cache(target);
        }
        MethodAccess sourceMethodAccess = methodMap.get(source.getClass());
        if (sourceMethodAccess == null) {
            sourceMethodAccess = cache(source);
        }
        List<String> fieldList = fieldMap.get(source.getClass());
        for (String field : fieldList) {
            String setKey = target.getClass().getName() + "." + "set" + field;
            Integer setIndex = methodIndexMap.get(setKey);
            if (setIndex != null) {
                String getKey = source.getClass().getName() + "." + "get" + field;
                int getIndex = methodIndexMap.get(getKey);
                // 参数一需要反射的对象
                // 参数二class.getDeclaredMethods 对应方法的index
                // 参数对三象集合
                Object invokeValue = sourceMethodAccess.invoke(source, getIndex);
                if (ignoreNull && invokeValue == null) {
                    continue;
                }
                targetMethodAccess.invoke(target, setIndex.intValue(), invokeValue);
            }
        }
    }

    // 单例模式
    private static MethodAccess cache(Object orgi) {
        synchronized (orgi.getClass()) {
            MethodAccess methodAccess = MethodAccess.get(orgi.getClass());
            List<Field> fields = getAllFields(orgi);
            List<String> fieldList = new ArrayList<>(fields.size());
            for (Field field : fields) {
                if (Modifier.isPrivate(field.getModifiers())
                        && !Modifier.isStatic(field.getModifiers())) { // 是否是私有的,是否是静态的
                    // 非公共私有变量
                    String fieldName = StringUtils.capitalize(field.getName()); // 获取属性名称
                    int getIndex = methodAccess.getIndex("get" + fieldName); // 获取get方法的下标
                    int setIndex = methodAccess.getIndex("set" + fieldName); // 获取set方法的下标
                    methodIndexMap.put(orgi.getClass().getName() + "." + "get"
                            + fieldName, getIndex); // 将类名get方法名,方法下标注册到map中
                    methodIndexMap.put(orgi.getClass().getName() + "." + "set"
                            + fieldName, setIndex); // 将类名set方法名,方法下标注册到map中
                    fieldList.add(fieldName); // 将属性名称放入集合里
                }
            }
            fieldMap.put(orgi.getClass(), fieldList); // 将类名,属性名称注册到map中
            methodMap.put(orgi.getClass(), methodAccess);
            return methodAccess;
        }
    }

    /**
     * 获取所有属性,包括 继承方式
     *
     * @param orgi
     * @return
     */
    private static List<Field> getAllFields(Object orgi) {
        List<Field> fields = Lists.newArrayList();
        //当前类自己的属性
        Field[] declaredFields4Local = orgi.getClass().getDeclaredFields();
        if (declaredFields4Local != null) {
            fields.addAll(Lists.newArrayList(declaredFields4Local));
        }
        /**
         * 获取继承类的属性
         */
        Class<?> superClass = orgi.getClass();
        do {
            superClass = superClass.getSuperclass();
            if (superClass == Object.class) {
                break;
            }
            if (superClass.getDeclaredFields() != null) {
                fields.addAll(Lists.newArrayList(superClass.getDeclaredFields()));
            }
        } while (superClass != Object.class);
        return fields;
    }
}

参考:https://blog.csdn.net/liaodehong/article/details/50379351

 

 

2、手写反射 的方式

对于实现,主要是使用 java 的反射机制。

首先需要构造一个实体类(TestModel.java):

package test;

public class TestModel {

private String prop1;    
private String prop2;
private String prop3;    


public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
public String getProp3() {
return prop3;
}
public void setProp3(String prop3) {
this.prop3 = prop3;
}

//用于输出字符串
@Override
public String toString() {

return "prop1:"+prop1+"\nprop2:"+prop2+"\nprop3:"+prop3;
}
}

 

然后紧接着创建一个合并相同实体的功能类():

package test;
import java.lang.reflect.Field;

public class CombineBeans {
    
    
    /**
     * 该方法是用于相同对象不同属性值的合并,如果两个相同对象中同一属性都有值,那么sourceBean中的值会覆盖tagetBean重点的值
     * @param sourceBean    被提取的对象bean
     * @param targetBean    用于合并的对象bean
     * @return targetBean,合并后的对象
     */
    private TestModel combineSydwCore(TestModel sourceBean,TestModel targetBean){
        Class sourceBeanClass = sourceBean.getClass();
        Class targetBeanClass = targetBean.getClass();
        
        Field[] sourceFields = sourceBeanClass.getDeclaredFields();
        Field[] targetFields = targetBeanClass.getDeclaredFields();
        for(int i=0; i<sourceFields.length; i++){
            Field sourceField = sourceFields[i]; 
       if(Modifier.isStatic(sourceField.getModifiers())){
        continue;
       } Field targetField
= targetFields[i];
       if(Modifier.isStatic(targetField.getModifiers())){
        continue;
       }  sourceField.setAccessible(
true); targetField.setAccessible(true); try { if( !(sourceField.get(sourceBean) == null) && !"serialVersionUID".equals(sourceField.getName().toString())){ targetField.set(targetBean,sourceField.get(sourceBean)); } } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } return targetBean; } //测试 combineBeans方法 public static void main(String[] args) { TestModel sourceModel = new TestModel(); // 第一个对象 TestModel targetModel = new TestModel(); // 第二个model对象 sourceModel.setProp1("1"); sourceModel.setProp2("1"); targetModel.setProp2("2"); targetModel.setProp3("2"); CombineBeans test = new CombineBeans(); test.combineSydwCore(sourceModel, targetModel); System.out.println(targetModel.toString()); } }

输出的结果如下:

根据控制台中打印结果发现:

原来的targetModel属性值:

prop1:null
prop2:2
prop3:2

合并之后的targetModel属性值:

prop1:1
prop2:1
prop3:2

targetModel中的 prop1 属性被 sourceModel 中的 prop1 属性填充;prop2 属性被 prop1 覆盖。

在后续使用中发现,应该排除 静态域,具体判断方法参考:https://blog.csdn.net/zhou8622/article/details/44038699

到此,over !!! ^_^

posted @ 2016-07-18 10:12  fight-ing  阅读(33487)  评论(0编辑  收藏  举报
Fork me on GitHub