通过反射对比两个对象值是否相同

本文介绍了一种通过反射来比较两个属于同一类且未重写equals方法的对象的方法。当对象属性包含数组、List、Set或Map时,会按照集合元素顺序进行比较。需要注意的是,如果集合中的元素相同但顺序不同(如List中的a、b与b、a),反射比较将认为这两个对象不相等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

适用情况:

两个对象属于同一个类,如果类没有重写equals方法,可通过反射对比对象属性值。如果对象的属性里面包含了数组、List、Set或者Map的时候,只会按顺序去对比这些集合里面的值,

比如里面对象里面有一个List属性,里面的值是 a、b,另外一个对象的属性值是b、a,虽然两个对象的List属性的值都是a、b,但是因为顺序不同,所以这里判断这两个对象值是不同的。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author yjy
 * @date 2022/3/29
 * 比较两个对象值是否相等
 */
public class BeanCompareUtils {
    private static final Logger logger = LoggerFactory.getLogger(BeanCompareUtils.class);

    private static List<String> baseTypes= Arrays.asList(
            String.class.getName(),
            Integer.class.getName(),
            Long.class.getName(),
            Double.class.getName(),
            Float.class.getName(),
            BigDecimal.class.getName(),
            Date.class.getName(),
            Timestamp.class.getName(),
            LocalDate.class.getName(),
            LocalDateTime.class.getName(),
            Boolean.class.getName(),
            Short.class.getName(),
            Byte.class.getName(),
            Character.class.getName(),
            BigInteger.class.getName()
    );

    /**
     * 比较两个对象值是否相等
     * @param p1
     * @param p2
     * @return
     */
    public static <P> boolean equals(Object p1,Object p2){
        if(p1==p2){
            return true;
        }
        else if(p1!=null && p2!=null){
            Class cls=p1.getClass();
            if(!p1.getClass().equals(p2.getClass())){
                return false;
            }
            //如果是基础类型数据
            if(baseTypes.contains(cls.getName())){
                return Objects.equals(p1,p2);
            }
            PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(cls);
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                Method readMethod = propertyDescriptor.getReadMethod();
                if(readMethod!=null){
                    Class<?> propertyType = propertyDescriptor.getPropertyType();
                    try {
                        Object value1 = readMethod.invoke(p1);
                        Object value2 = readMethod.invoke(p2);
                        //如果是基础类数据
                        if(propertyType.isPrimitive() || baseTypes.contains(propertyType.getName())) {
                            if(!Objects.equals(value1, value2)){
                                return false;
                            }
                        }
                        //如果是数组
                        else if(propertyType.isArray()){
                            if(value1==null && value2==null){
                            }else  if(value1!=null && value2!=null ){
                                boolean b = equalCollection((Object[]) value1, (Object[]) value2);
                                if(Boolean.FALSE.equals(b)){
                                    return false;
                                }
                            }else{
                                return false;
                            }
                        }
                        //如果是List、Set
                        else if(Collection.class.isAssignableFrom(propertyType)){
                            if(value1==null && value2==null){

                            }else if(value1!=null && value2!=null){
                                boolean b = equalCollection(((Collection) value1).toArray(), ((Collection) value2).toArray());
                                if(Boolean.FALSE.equals(b)){
                                    return false;
                                }
                            }else{
                                return false;
                            }
                        }
                        else if(Map.class.isAssignableFrom(propertyType)){
                            if(value1==null && value2==null){

                            }else if(value1!=null && value2!=null){
                                boolean b = equalMap((Map) value1, (Map) value2);
                                if(Boolean.FALSE.equals(b)){
                                    return false;
                                }
                            }else{
                                return false;
                            }
                        }else{
                            boolean b = equals(value1, value2);
                            if(Boolean.FALSE.equals(b)){
                                return false;
                            }
                        }
                    } catch (Exception e){
                        logger.error("反射获取对象属性值报错",e);
                        return false;
                    }
                }
            }
        }else{
            return false;
        }

        return true;
    }

    private static boolean equalCollection(Object[] c1,Object[] c2){
        if(c1.length!=c2.length){
            return false;
        }
        for(int i=0;i<c1.length;i++){
            boolean b=equals(c1[i],c2[i]);
            if(Boolean.FALSE.equals(b)){
                return false;
            }
        }
        return true;
    }

    private static boolean equalMap(Map m1,Map m2){
        if(m1.size()!=m2.size()){
            return false;
        }
        for (Object key : m1.keySet()) {
            if(!m2.containsKey(key)){
                return false;
            }
            Object value1 = m1.get(key);
            Object value2=m2.get(key);
            boolean b=equals(value1,value2);
            if(Boolean.FALSE.equals(b)){
                return false;
            }
        }
        return true;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值