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());
            }
        }
    }
}
相关推荐
名字还没想好☜33 分钟前
Go 的 time.After 在 select 循环里内存泄漏:定时器堆积原理与 timer.Reset 正确姿势
java·数据库·golang·go·goroutine
码农coding38 分钟前
android12 systemUI 之锁屏
android
圆山猫1 小时前
[Virtualization](三):RISC-V H-extension 与 Guest 执行模式
android·java·risc-v
caishenzhibiao1 小时前
期货先行者主图 同花顺期货通指标
java·c语言·c#
爱笑鱼1 小时前
Binder(七):getCallingUid() 读到的是谁?clearCallingIdentity() 又清掉了什么?
android
史呆芬1 小时前
分布式事务实战:微服务跨服务数据一致性解决方案
java·后端·spring cloud
IT界的老黄牛1 小时前
限流命中后该怎么办:直接丢、阻塞等待、延迟重投三种姿势的取舍
java·rocketmq·redisson·令牌桶·削峰·分布式限流
daad7772 小时前
记录matlab状态机demo
java·网络·matlab
牡丹雅忻13 小时前
AES 加密模式演进:从 ECB、CBC 到 GCM 的 C# 深度实践
java·开发语言·c#
学者猫头鹰3 小时前
Java 8 核心新特性
java