代码之家  ›  专栏  ›  技术社区  ›  jaudo

使用反射比较不同类的对象

  •  5
  • jaudo  · 技术社区  · 7 年前

    class Bean1 {
       int id;
    }
    
    class Bean2 {
       int id;
    }
    

    我想比较每个类的对象,而不用为每个属性编写比较代码。 This thread 解释如何比较两个对象,但在我的例子中,这失败了,因为它们不是同一类的实例。

    EqualsBuilder.reflectionEquals(new Bean1(1), new Bean2(1));
    

    有没有其他方法可以合并对象并忽略对象类?

    4 回复  |  直到 7 年前
        1
  •  2
  •   jaudo    7 年前

    ReflectionToStringBuilder ,因为它提供了 ToStringStyle.NO_CLASS_NAME_STYLE 选项

    Assert.assertEquals(
       new ReflectionToStringBuilder(bean1, ToStringStyle.NO_CLASS_NAME_STYLE).toString(),
       new ReflectionToStringBuilder(bean2, ToStringStyle.NO_CLASS_NAME_STYLE).toString());
    
        2
  •  1
  •   GhostCat    7 年前

    除非您找到这样做的库,否则您始终可以编写自己的反射代码来满足您的需要:

    • 查询要比较的对象上的字段
    • 如果两组字段名相等,则比较它们的内容
    • 不考虑实际的类

    如果您真的在处理这样的“简单”bean类,那么自己实现它实际上可能不是什么大问题。

    或者,您可以创建一个生成器,如

    public Bean1 from(Bean2 incoming) { ...
    

    如果您知道自己的类,您可以将所有值从一个Bean2“拉”到一个Bean1实例中,然后您可以比较两个Bean1实例。

    但当然,这种想法是没有帮助的(它要求您编写代码来处理所有字段,或者再次使用反射),但我们可以轻松地将其扩展到非反射方式:例如使用GSON将Bean2序列化为JSON。然后将该JSON字符串反序列化为Bean1!

    因此:如果您没有找到一个基于反射的库可以忽略该类,那么您应该能够通过JSON序列化来访问同一类的两个对象。

        3
  •  1
  •   raven1981    7 年前

    反射实现将很容易获得每个对象的所有字段,并比较其值。这里有一个例子:

    public static boolean compareObjects(Object o1, Object o2) {        
            try {
                List<Field> fields1 = getFields(o1);
                List<Field> fields2 = getFields(o2);
                boolean found;
                Field field2Temp = null;
                for (Field field1 : fields1) {
                    found = false;
                    for (Field field2 : fields2) {
                        if (field1.getName().equals(field2.getName())) {
                            if (!field1.get(o1).equals(field2.get(o2))) {
                                System.out.println("Value " + field1.get(o1) + " for field " + field1 + " does not match the value " + field2.get(o2) + " for field " + field2);
                                return false;
                            }
                            field2Temp = field2;
                            found = true;
                        }
                    }
                    if (!found) {
                        System.out.println("Field " + field1 + " has not been found in the object " + o2.getClass());
                        return false;
                    } else {
                        fields2.remove(field2Temp);
                    }
                }
                if (fields2.size() > 0) {
                    for (Field field : fields2) {
                        System.out.println("Field " + field + " has not been found in the object " + o1.getClass());
                    }
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
    
        private static List<Field> getFields(Object o) {
            Field[] fields = o.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
            }
            return new ArrayList<>(Arrays.asList(fields));
        }
    

    如您所见,我正在强制字段匹配,因此如果在另一个对象中找不到一个字段,该方法将返回false,但您可以根据需要轻松更改它。

    这段代码给出了两个对象不同时问题所在的详细信息。

    执行此命令时:

    public static void main(String args[]){
            Bean1 bean1 = new Bean1(1);
            Bean2 bean2 = new Bean2(1);
            System.out.println("Equals? " + bean1.equals(bean2));
            System.out.println("Reflection equals? " + compareObjects(bean1, bean2));
            bean2 = new Bean2(2);
            System.out.println("Equals? " + bean1.equals(bean2));
            System.out.println("Reflection equals? " + compareObjects(bean1, bean2));
        }
    

    您得到的结果是:

    Equals? false
    Reflection equals? true
    Equals? false
    Value 1 for field private int com.test.so.Bean1.id does not match the value 2 for field private int com.test.so.Bean2.id
    Reflection equals? false
    

        4
  •  0
  •   imperezivan    7 年前

    如果实体具有公共属性,请使用抽象类并重写equals方法

    abstract class Bean {
       private int id;
    
    
       public int getId(){
          return id;
       }    
    
       @Override
       boolean equals(Object obj){
          if(obj is null){
            return false; 
          } else if (obj instanceof Bean) {
              return ((Integer)this.getId()).equals((Bean)obj).getId());
          } else {
             return false;
          }
       }
    }
    
    class Bean1 extends Bean {
       //int id;
    }
    
    class Bean2 extends Bean  {
       //int id;
    }