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());
            }
        }
    }
}
相关推荐
程序员陆业聪6 小时前
技术选型决策树:什么团队、什么项目该选什么框架 | 跨平台框架深度对决(4)
android
xqqxqxxq7 小时前
Java AI智能P图工具技术笔记
java·人工智能·笔记
谷雨不太卷7 小时前
进程的状态码
java·前端·算法
顾温7 小时前
default——C#/C++
java·c++·c#
空中海7 小时前
02 ArkTS 语言与工程规范
java·前端·spring
楚国的小隐士7 小时前
在AI时代,如何从0接手一个项目?
java·ai·大模型·编程·ai编程·自闭症·自闭症谱系障碍·神经多样性
yaki_ya7 小时前
yaki-C语言:从概念基础到内存解析---数组(array)完全指南
java·c语言·算法
刃神太酷啦7 小时前
扒透 STL 底层!map/set 如何封装红黑树?迭代器逻辑 + 键值限制全手撕----《Hello C++ Wrold!》(23)--(C/C++)
java·c语言·javascript·数据结构·c++·算法·leetcode
亚历克斯神7 小时前
Java 25 模式匹配增强:让代码更简洁优雅
java·spring·微服务
星辰徐哥7 小时前
Rust异步测试与调试的实践指南
android·java·rust