通过Java反射机制获取对象差异工具类

Java反射机制获取对象差异工具类

今天遇到一个需求,需要记录一下操作数据的动作,于是想到了可以使用java的反射来实现

工具类实现

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 字段差异对比工具类
 */
public class ReflectionDiffUtil {

    /**
     * 获取对象差异集合
     * @param oldObj 旧对象
     * @param newObj 新对象
     * @return 差异集合
     */
    public static List<FieldDiff> getDiffList(Object oldObj, Object newObj) {
        List<FieldDiff> diffList = new ArrayList<>();
        
        if (oldObj == null || newObj == null) {
            throw new IllegalArgumentException("对比对象不能为空");
        }

        if (!oldObj.getClass().equals(newObj.getClass())) {
            throw new IllegalArgumentException("对比对象类型不一致");
        }

        Class<?> clazz = oldObj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            try {
                field.setAccessible(true);
                
                Object oldValue = field.get(oldObj);
                Object newValue = field.get(newObj);
                
                if (!Objects.equals(oldValue, newValue)) {
                    String fieldName = getFieldChineseName(field);
                    diffList.add(new FieldDiff(
                            fieldName, 
                            oldValue, 
                            newValue
                    ));
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException("字段访问失败: " + field.getName(), e);
            }
        }
        
        return diffList;
    }

    /**
     * 获取字段中文名称
     */
    private static String getFieldChineseName(Field field) {
        if (field.isAnnotationPresent(FieldName.class)) {
            FieldName annotation = field.getAnnotation(FieldName.class);
            return annotation.value();
        }
        return field.getName(); // 没有注解时返回字段名
    }

    /**
     * 字段差异信息类
     */
    public static class FieldDiff {
        private String fieldName;  // 中文字段名
        private Object oldValue;   // 旧值
        private Object newValue;   // 新值

        public FieldDiff(String fieldName, Object oldValue, Object newValue) {
            this.fieldName = fieldName;
            this.oldValue = oldValue;
            this.newValue = newValue;
        }

        // Getter方法省略...
    }

    /**
     * 字段中文名注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface FieldName {
        String value();
    }
}

使用示例

1. 定义实体类

public class User {
    @ReflectionDiffUtil.FieldName("用户ID")
    private Long id;
    
    @ReflectionDiffUtil.FieldName("用户姓名")
    private String name;
    
    @ReflectionDiffUtil.FieldName("用户年龄")
    private Integer age;

    // 构造方法/getter/setter省略...
}

2. 创建新旧对象

User oldUser = new User();
oldUser.setId(1L);
oldUser.setName("张三");
oldUser.setAge(25);

User newUser = new User();
newUser.setId(1L);
newUser.setName("李四");
newUser.setAge(30);

3. 获取差异列表

List<ReflectionDiffUtil.FieldDiff> diffs = 
    ReflectionDiffUtil.getDiffList(oldUser, newUser);

4. 输出结果

[用户姓名] 旧值:张三 → 新值:李四
[用户年龄] 旧值:25 → 新值:30

实现说明

  1. 注解定义

    • @FieldName 注解用于标记字段的中文名称
    • 支持在运行时通过反射读取注解信息
  2. 核心方法

    • getDiffList() 方法使用反射遍历所有字段
    • 通过 Objects.equals() 安全比较字段值
    • 自动跳过值相同的字段
  3. 异常处理

    • 检查对象类型一致性
    • 处理字段访问异常
    • 空对象校验

扩展建议

1. 忽略字段

@FieldName(value = "创建时间", ignore = true)
private Date createTime;

2. 深度对比

if (field.getType().isPrimitive()) {
    // 基础类型直接比较
} else {
    // 递归调用 getDiffList()
}

3. 自定义比较器

public interface FieldComparator {
    boolean compare(Object oldVal, Object newVal);
}
posted @ 2025-02-28 18:10  PromiseForYou  阅读(45)  评论(0)    收藏  举报