java 对比分析对象是否有变化

在项目中大家应该遇到过这种问题,需要分析对象是否发生变化,发生变化后,具体是哪个字段发生变化

下面提供相关的工具类,大家拿来用就行了

java 复制代码
package com.eternal.base.utils;

import androidx.databinding.ObservableBoolean;
import androidx.databinding.ObservableField;
import androidx.databinding.ObservableInt;

import com.eternal.framework.utils.KLog;

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

import io.reactivex.Observable;

/**
 * 用于分析对象是否发生变化,发生变化后,具体是哪个字段发生变化
 */
public class ObjectChangeDetector {

    private String tag = "ObjectChangeDetector";
    private int lastHash = 0;
    private Object lastObject = null;

    public ObjectChangeDetector(Object object) {
        this.lastObject = object;
        this.lastHash = Objects.hashCode(object);
    }

    public void checkAndReport(Object newObject) {
        int newHash = Objects.hashCode(newObject);

        // 1. 快速预检:通过 Hash 判断是否有变化
        if (newHash == this.lastHash) {
            KLog.d(tag, "Hash 值一致,对象无变化。");
            return;
        }

        // 2. Hash 变化了,进行详细对比
        KLog.d(tag, "Hash 值变化 (" + this.lastHash + " -> " + newHash + "),开始分析差异...");
        if (this.lastObject != null) {
            // 使用上面介绍的 JSON 或 Javers 方法进行 Diff
            compareObjects(this.lastObject, newObject);
        }
        // 3. 更新状态
        this.lastHash = newHash;
        this.lastObject = newObject;
    }

    private void compareObjects(Object a, Object b) {
        Field[] fieldsA = a.getClass().getDeclaredFields();
        Field[] fieldsB = b.getClass().getDeclaredFields();
        for (Field field : fieldsA) {
            field.setAccessible(true);
            String fieldName = field.getName();
            try {
                Field fieldFromB = Observable.fromArray(fieldsB).filter(it->fieldName.contentEquals(it.getName())).blockingFirst();
                if (fieldFromB == null) {
                    KLog.d(tag, b.getClass().getSimpleName() + " 的字段 " + fieldName + " 不存在");
                    continue;
                }
                fieldFromB.setAccessible(true);
                // 获取静态字段的值
                Object valueA = field.get(a);
                Object valueB = fieldFromB.get(b);
                KLog.d(tag, b.getClass().getSimpleName() + " 的字段 " + fieldName + ", 类型:" + valueA.getClass().getSimpleName());
                if (valueA instanceof Integer && valueB instanceof Integer) {
                    if ((int)valueA != (int)valueB) {
                        String msg = a.getClass().getSimpleName() + "." + fieldName + ": " + valueA + " -> " + valueB;
                        KLog.d(tag, msg);
                    }
                }
                else if (valueA instanceof ObservableInt && valueB instanceof ObservableInt) {
                    if (((ObservableInt)valueA).get() != ((ObservableInt)valueB).get()) {
                        String msg = a.getClass().getSimpleName() + "." + fieldName + ": " + ((ObservableInt) valueA).get() + " -> " + ((ObservableInt) valueB).get();
                        KLog.d(tag, msg);
                    }
                }
                else if (valueA instanceof ObservableBoolean && valueB instanceof ObservableBoolean) {
                    if (((ObservableBoolean)valueA).get() != ((ObservableBoolean)valueB).get()) {
                        String msg = a.getClass().getSimpleName() + "." + fieldName + ": " + ((ObservableBoolean) valueA).get() + " -> " + ((ObservableBoolean) valueB).get();
                        KLog.d(tag, msg);
                    }
                }
                else if (valueA instanceof ObservableField && valueB instanceof ObservableField) {
                    valueA = ((ObservableField<?>) valueA).get();
                    valueB = ((ObservableField<?>) valueB).get();
                    if (valueA instanceof String && valueB instanceof String) {
                        if (!((String) valueA).contentEquals((String)valueB)) {
                            String msg = a.getClass().getSimpleName() + "." + fieldName + ": " + valueA + " -> " + valueB;
                            KLog.d(tag, msg);
                        }
                    } else if (valueA.getClass().getSimpleName().contentEquals("PortItem") && valueB.getClass().getSimpleName().contentEquals("PortItem")) {
                        compareObjects(valueA, valueB);
                    }
                }
            } catch (Exception e) {
                KLog.e(tag,e + ", field name:" + field.getName());
            }
        }
    }
}
相关推荐
tianyu2341 小时前
Java 正则表达式终极指南:从 Pattern 到 Matcher,从双重转义到性能优化,一篇全搞定
java·开发语言·正则表达式·group·find·pattern·matcher
Emily156853598703 小时前
Emerson 1C31129G03 Analog Input Module
java·开发语言·前端·plc·emerson·1c31129g03·input module
就叫_这个吧8 小时前
Java递归方法实现面包屑导航
java·开发语言
fīɡЙtīиɡ ℡8 小时前
AI 应用系统设计
java·开发语言·人工智能
城管不管8 小时前
重生——第十一次面试之挖财一面2026.8.19已OC
java·服务器·jvm·数据库·spring·面试·职场和发展
码匠许师傅8 小时前
【C++ 面试真题】26. 聊聊 C++ 的智能指针
java·c++·面试
AI绘画哇哒哒9 小时前
【建议收藏!】35岁后端血泪忠告,这3类人别硬转Agent(过来人亲述)
java·人工智能·后端·ai·程序员·大模型·agent
最强小杰9 小时前
gpt-5.6-sol 频繁报 503 怎么办?区分容量熔断和限速 429 的排查方法 + 可复用 retry wrapper
java·人工智能·gpt·ai
夜雪一千11 小时前
MySQL 全局锁是什么?原理、风险、备份踩坑完整实战
android·mysql·adb
吠品11 小时前
Wine 在 Linux 上运行 Windows 软件完整指南
java·linux·服务器