Java对象属性比较工具类(可用)

摘要:

在Java开发过程中,我们经常需要对两个对象的属性进行对比。本文将介绍一款实用的工具类BeanCompareUtil,它可以帮助我们高效地进行对象属性比较,并详细讲解其实现原理及使用方法。
一、背景
在日常开发中,我们经常遇到以下场景:比较两个对象的属性是否相等。如果手动编写代码进行属性比较,不仅效率低下,而且容易出错。为此,本文将介绍一款强大的工具类BeanCompareUtil,它可以帮助我们快速、准确地比较对象属性。

// 假设 BizAppealTrack 有 getter 方法
String taskNum = bizAppealTrack.getTaskNum();
String nodeTime = bizAppealTrack.getNodeTime();
String deptName = bizAppealTrack.getDeptName();
String content = bizAppealTrack.getContent();

boolean isSameData = tempBizAppealTrackList.stream()
.anyMatch(appealTrack -> {
    return Objects.equals(taskNum, appealTrack.getTaskNum()) &&
           Objects.equals(nodeTime, appealTrack.getNodeTime()) &&
           Objects.equals(deptName, appealTrack.getDeptName()) &&
           Objects.equals(content, appealTrack.getContent());
});

二、BeanCompareUtil实现原理

BeanCompareUtil工具类主要依赖于Java反射机制和Spring框架的ReflectionUtils工具类。以下是BeanCompareUtil的核心实现原理:

  1. 使用Map缓存字段信息,提高查找效率。
  2. 通过反射获取指定类的所有字段,并存储到缓存中。
  3. 比较两个对象指定字段的值是否相等。
    三、BeanCompareUtil使用方法
  4. 引入依赖
    首先,在项目中引入Spring框架依赖:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.9</version>
</dependency>

创建工具类

将以下代码复制到项目中,创建BeanCompareUtil类:

// BeanCompareUtil代码
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class BeanCompareUtil {

    // 使用缓存来存储字段,避免重复查找
    private static final Map<Class<?>, Map<String, Field>> fieldCache = new HashMap<>();

    /**
     * equalsByFields方法比较两个对象中指定字段的值是否相等。
     * 如果源对象或目标对象为null,则直接返回比较结果。
     * 如果源对象和目标对象的类型不同,则返回false。
     * 否则,使用缓存的字段映射来获取字段,并比较它们的值。
     * 如果任何字段的值不相等,则返回false。
     * 如果所有字段的值都相等,则返回true。
     *
     * @param src        源对象
     * @param target     目标对象
     * @param fieldNames 需要比较的字段名称数组
     * @return 如果指定字段相等返回true,否则返回false
     */
    public static boolean equalsByFields(Object src, Object target, String... fieldNames) {
        // 如果源对象或目标对象为null,则直接返回比较结果
        if (src == null || target == null) {
            return src == target;
        }
        // 如果源对象和目标对象的类型不同,则返回false
        if (!src.getClass().equals(target.getClass())) {
            return false;
        }

        // 使用缓存的字段映射来获取字段
        Map<String, Field> fields = getFieldMap(src.getClass());
        for (String fieldName : fieldNames) {
            Field field = fields.get(fieldName);
            // 如果字段未找到,则抛出异常
            if (field == null) {
                throw new IllegalArgumentException("Field " + fieldName + " not found in class " + src.getClass());
            }
            // 使字段可访问
            ReflectionUtils.makeAccessible(field);
            // 获取字段值并比较
            Object srcValue = ReflectionUtils.getField(field, src);
            Object targetValue = ReflectionUtils.getField(field, target);
            // 如果字段值不相等,则返回false
            if (!Objects.equals(srcValue, targetValue)) {
                return false;
            }
        }
        // 如果所有字段的值都相等,则返回true
        return true;
    }

    /**
     * getFieldMap方法获取指定类的所有字段映射。
     * 使用缓存来避免重复查找字段。
     *
     * @param clazz 类的Class对象
     * @return 包含字段映射的Map
     */
    private static Map<String, Field> getFieldMap(Class<?> clazz) {
        // 使用缓存来获取字段映射
        Map<String, Field> fieldMap = fieldCache.computeIfAbsent(clazz, k -> {
            Map<String, Field> newFieldMap = new HashMap<>();
            // 获取类的所有声明字段
            Field[] declaredFields = clazz.getDeclaredFields();
            // 遍历字段并添加到映射中
            for (Field field : declaredFields) {
                newFieldMap.put(field.getName(), field);
            }
            // 返回新的字段映射
            return newFieldMap;
        });
        // 返回缓存的字段映射
        return fieldMap;
    }

    // main 方法与之前相同
    // public static void main(String[] args) {
    //     // 示例对象
    //     Person p1 = new Person("Alice", 30);
    //     Person p2 = new Person("Alice", 30);
    //     Person p3 = new Person("Bob", 25);
    //
    //     // 比较p1和p2的name字段是否相等
    //     boolean isSame = equalsByFields(p1, p2, "name", "age");
    //     System.out.println("p1和p2的字段是否相等: " + isSame);
    //
    //     // 比较p1和p3的name字段是否相等
    //     isSame = equalsByFields(p1, p3, "name", "age");
    //     System.out.println("p1和p3的字段是否相等: " + isSame);
    // }
}

使用示例

以下是一个使用BeanCompareUtil进行对象属性比较的示例:

public class Main {
    public static void main(String[] args) {
        // 示例对象
        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Alice", 30);
        Person p3 = new Person("Bob", 25);
        // 比较p1和p2的name字段是否相等
        boolean isSame = BeanCompareUtil.equalsByFields(p1, p2, "name", "age");
        System.out.println("p1和p2的字段是否相等: " + isSame);
        // 比较p1和p3的name字段是否相等
        isSame = BeanCompareUtil.equalsByFields(p1, p3, "name", "age");
        System.out.println("p1和p3的字段是否相等: " + isSame);
    }
}
class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 省略getter和setter方法
}

运行结果

p1和p2的字段是否相等: true
p1和p3的字段是否相等: false

四、总结

BeanCompareUtil是一款实用的Java对象属性比较工具类,它基于反射机制和Spring框架的ReflectionUtils工具类实现。通过使用BeanCompareUtil,我们可以轻松地进行对象属性比较,提高开发效率。在实际项目中,我们可以根据需求对BeanCompareUtil进行扩展,以满足更多场景的需求。

补充测试

// 下面是一个`main`测试案例,用于校验`BeanCompareUtil`类的健壮性。这个测试案例将创建几个对象,并对它们进行字段比较。测试案例会包括以下几种情况:
// 1. 比较相同字段值的对象。
// 2. 比较不同字段值的对象。
// 3. 比较一个字段值为`null`和一个非`null`的对象。
// 4. 比较两个`null`对象。
// 5. 比较一个`null`对象和一个非`null`对象。
// 6. 比较不同类型的对象。
// 7. 比较不存在的字段。

public class BeanCompareUtilTest {
    public static void main(String[] args) {
        // 示例对象
        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Alice", 30);
        Person p3 = new Person("Bob", 25);
        Person p4 = new Person(null, 30);
        Person p5 = null;
        Person p6 = new Person("Alice", 30);
        OtherClass oc = new OtherClass("Alice", 30);
        // 比较p1和p2的name和age字段是否相等
        boolean isSame = BeanCompareUtil.equalsByFields(p1, p2, "name", "age");
        System.out.println("p1和p2的字段是否相等: " + isSame);
        // 比较p1和p3的name和age字段是否相等
        isSame = BeanCompareUtil.equalsByFields(p1, p3, "name", "age");
        System.out.println("p1和p3的字段是否相等: " + isSame);
        // 比较p1和p4的name字段是否相等(p4的name为null)
        isSame = BeanCompareUtil.equalsByFields(p1, p4, "name");
        System.out.println("p1和p4的name字段是否相等: " + isSame);
        // 比较p5和p5(两个null对象)
        isSame = BeanCompareUtil.equalsByFields(p5, p5, "name", "age");
        System.out.println("p5和p5的字段是否相等: " + isSame);
        // 比较p1和p5(p5为null)
        isSame = BeanCompareUtil.equalsByFields(p1, p5, "name", "age");
        System.out.println("p1和p5的字段是否相等: " + isSame);
        // 比较p1和oc(不同类型的对象)
        try {
            isSame = BeanCompareUtil.equalsByFields(p1, oc, "name", "age");
            System.out.println("p1和oc的字段是否相等: " + isSame);
        } catch (IllegalArgumentException e) {
            System.out.println("比较p1和oc时发生错误: " + e.getMessage());
        }
        // 比较p1和p6的不存在的字段
        try {
            isSame = BeanCompareUtil.equalsByFields(p1, p6, "nonExistentField");
            System.out.println("p1和p6的nonExistentField字段是否相等: " + isSame);
        } catch (IllegalArgumentException e) {
            System.out.println("比较p1和p6的nonExistentField字段时发生错误: " + e.getMessage());
        }
    }
    // Person类定义
    public static class Person {
        private String name;
        private int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        // Getters and Setters
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    // OtherClass类定义
    public static class OtherClass {
        private String name;
        private int age;
        public OtherClass(String name, int age) {
            this.name = name;
            this.age = age;
        }
        // Getters and Setters
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
}

图片.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值