Java对比两个实体的差异

有时候需要对比2个实体的值是否一致,可以用与一下方法。摘自大神博客。

package com.xx;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.*;


public class CompareFileds {

    /**
     * 比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个list分别存obj1,obj2此属性名的值
     * @param obj1 进行属性比较的对象1
     * @param obj2 进行属性比较的对象2
     * @param compareArr 选择要比较的属性数组
     * @return 属性差异比较结果map
     */
    public static Map<String, Map> compareFields(Object obj1, Object obj2, String[] compareArr) {
        try {
            //装返回值得
            Map<String, Map> map = new LinkedHashMap<>();
            //需要对比的字段list
            List<String> ignoreList = null;
            if (compareArr != null && compareArr.length > 0) {
                // array转化为list
                ignoreList = Arrays.asList(compareArr);
            }
            // 只有两个对象都是同一类型的才有可比性
            if (obj1.getClass() == obj2.getClass()) {
                Class clazz = obj1.getClass();
                // 获取object的属性描述
                PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz,
                        Object.class).getPropertyDescriptors();
                // 这里就是所有的属性了
                for (PropertyDescriptor pd : pds) {
                    // 属性名
                    String name = pd.getName();
                    // 如果当前属性选择进行比较,跳到下一次循环
                    if (ignoreList != null && ignoreList.contains(name)) {
                        // get方法
                        Method readMethod = pd.getReadMethod();
                        // 在obj1上调用get方法等同于获得obj1的属性值
                        Object objBefore = readMethod.invoke(obj1);
                        // 在obj2上调用get方法等同于获得obj2的属性值
                        Object objAfter = readMethod.invoke(obj2);
                        if (objBefore instanceof Timestamp) {
                            objBefore = new Date(((Timestamp) objBefore).getTime());
                        }
                        if (objAfter instanceof Timestamp) {
                            objAfter = new Date(((Timestamp) objAfter).getTime());
                        }
                        if (objBefore == null && objAfter == null) {
                            continue;
                        } else if (objBefore == null && objAfter != null) {
                            Map m = new LinkedHashMap();
                            m.put("objBefore",objBefore);
                            m.put("objAfter",objAfter);
                            map.put(name, m);
                            continue;
                        }
                        // 比较这两个值是否相等,不等则放入map
                        if (!objBefore.equals(objAfter)) {
                            Map m = new LinkedHashMap();
                            m.put("objBefore",objBefore);
                            m.put("objAfter",objAfter);
                            map.put(name, m);
                        }
                    }
                }
            }else {
                System.out.println("对象类型不一致,不能完成对比");
            }
            return map;
        } catch (Exception e) {
            System.out.println("错误");
            return null;
        }
    }
}

结果:

<think>我们正在寻找一种方法来复制两个实体对象中具有相同名称和类型的属性值。 根据引用[2][3][4],我们看到有几种工具方法可以实现: 1. org.springframework.beans.BeanUtils.copyProperties(Object source, Object target) 2. org.apache.commons.beanutils.BeanUtils.copyProperties(Object dest, Object src) [注意参数顺序与Spring相反] 这两个工具类都可以将源对象(source)的属性值复制到目标对象(target)的同名属性中。它们会忽略类型不匹配的属性,只复制那些名称相同且类型兼容的属性。 引用[3]给出了一个示例,展示了如何将一个Source对象的属性复制到Target对象中,即使这两个类不是同一个类,只要它们有相同的属性名和类型(或者兼容的类型)即可。 因此,我们可以使用Spring的BeanUtils或者Apache Commons BeanUtils来实现。 另外,引用[1]中提到防御性复制,如果我们的实体类包含可变对象(如Date、集合等),我们可能需要考虑进行深拷贝以避免共享引用带来的问题。但上述工具方法默认是浅拷贝。 因此,具体步骤: 1. 添加相应的依赖(Spring BeanUtils或Apache Commons BeanUtils)。 2. 调用对应的copyProperties方法。 注意:两个工具类的参数顺序不同,使用时要小心。 示例代码(使用Spring BeanUtils): ```java import org.springframework.beans.BeanUtils; // 假设有两个类 SourceClass 和 TargetClass SourceClass source = new SourceClass(); // 设置source属性... TargetClass target = new TargetClass(); // 将source中的属性复制到target中(同名且类型兼容的属性) BeanUtils.copyProperties(source, target); ``` 示例代码(使用Apache Commons BeanUtils): ```java import org.apache.commons.beanutils.BeanUtils; SourceClass source = new SourceClass(); TargetClass target = new TargetClass(); BeanUtils.copyProperties(target, source); // 注意:这里第一个参数是目标,第二个是源 ``` 如果属性是基本类型或String等不可变类型,浅拷贝没有问题。但如果属性是可变对象,且我们希望目标对象和源对象互不影响,则需要深拷贝。深拷贝可以通过序列化、手动复制或使用工具(如Dozer)来实现,但这不是当前问题所要求的。 根据用户需求,我们只需要复制相同类型和名称的参数(属性),所以使用上述工具即可。 另外,引用[1]中提到“防御性复制”,如果我们复制的对象会被用于不可变对象中,那么可能需要考虑进行防御性复制,以避免外部修改影响对象内部状态。但是,在普通的实体复制中,我们通常只需要浅拷贝。 因此,推荐使用Spring BeanUtils,因为它更常用,尤其是在Spring项目中。 如果用户没有使用Spring,可以考虑使用Apache Commons BeanUtils,但要注意其性能问题(通常较慢)和异常处理(需要处理受检异常)。 总结: 使用Spring BeanUtils.copyProperties(source, target) 或 Apache Commons BeanUtils.copyProperties(target, source) 方法。 </think>根据引用内容,在 Java 中复制两个实体对象中相同名称和类型的属性,推荐以下方法: ### 推荐方法一:使用 Spring BeanUtils ```java import org.springframework.beans.BeanUtils; class Source { private String name; private int age; // getters/setters } class Target { private String name; // 同名同类型属性 private String address; // getters/setters } // 复制操作 Source source = new Source("Tom", 20); Target target = new Target(); BeanUtils.copyProperties(source, target); // 关键方法 System.out.println(target.getName()); // 输出 "Tom" [^3][^4] ``` **特点**: 1. 自动复制源对象中所有**同名且类型兼容**的属性 2. 忽略目标对象独有的属性(如 `address`) 3. **参数顺序**:`copyProperties(源对象, 目标对象)` [^4] ### 推荐方法二:使用 Apache Commons BeanUtils ```java import org.apache.commons.beanutils.BeanUtils; // 参数顺序与Spring相反! BeanUtils.copyProperties(target, source); // 目标对象在前 [^2] ``` ### 注意事项 1. **浅拷贝问题**:两个工具默认执行**浅拷贝**,若属性包含可变对象(如 `Date`),需额外处理深拷贝[^1] 2. **防御性复制**:涉及敏感数据时,建议对复制结果进行防御性复制[^1] 3. **类型兼容**: - 支持基本类型和包装类型的自动转换(如 `int` → `Integer`) - 不支持不同类型间的强制转换(如 `String` → `int`) 4. **性能考虑**:频繁调用时,Spring BeanUtils 性能优于 Apache 版本 ### 扩展场景 当需要深度复制或处理复杂类型时: ```java // 深拷贝示例(使用JSON序列化) ObjectMapper mapper = new ObjectMapper(); Target target = mapper.readValue(mapper.writeValueAsString(source), Target.class); ``` --- ### 相关问题 1. 如何处理实体复制时的深拷贝需求? 2. BeanUtils 复制属性时遇到类型不匹配该如何解决? 3. 防御性复制在实体复制场景中的具体实现方式是? 4. 如何验证两个实体对象间的属性复制是否完整? [^1]: 参数验证与防御性复制的最佳实践 [^2]: Apache Commons 与 Spring 的参数顺序差异 [^3]: 不同类对象的同名属性复制示例 [^4]: Spring BeanUtils 的基本用法
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值