我有两个对象具有完全相同的属性。别问我为什么,这是生成的代码,我必须处理。
class Bean1 {
int id;
}
class Bean2 {
int id;
}
我想比较每个类的对象,而不必为每个属性编写比较代码。 This thread解释了如何比较两个对象,但是在我的案例中,这失败了,因为它们不是同一类的实例。
此代码返回false:
EqualsBuilder.reflectionEquals(new Bean1(1), new Bean2(1));
还有另一种比较对象并忽略对象类的方法吗?
答案 0 :(得分:1)
除非找到可以执行此操作的库,否则您始终可以编写自己的反射代码来满足您的需要:
如果您真的在处理这样的“简单” bean类,那么自己实现可能就没什么大不了了。
或者,您可以创建类似的生成器
public Bean1 from(Bean2 incoming) { ...
如果您知道自己的类,则可以将Bean2中的所有值“拉”入Bean1实例,然后可以比较两个Bean1实例。
但是,这个想法当然无济于事(它要求您编写代码来处理所有字段,或者再次使用反射),但是我们可以轻松地将其扩展为非反射方式:将Bean2序列化为JSON,例如使用GSON。然后将该JSON字符串反序列化为Bean1!
因此:如果您找不到一个忽略该类的基于反射的库,则应该能够进行JSON序列化以获取相同类的两个对象。
答案 1 :(得分:1)
我终于可以使用Apache Common Lang的ReflectionToStringBuilder来做到这一点,因为它提供了ToStringStyle.NO_CLASS_NAME_STYLE选项。
此外,当我在JUnit测试中使用它时,它很有用,因为如果对象不同,我将能够看到哪个字段不同。
Assert.assertEquals(
new ReflectionToStringBuilder(bean1, ToStringStyle.NO_CLASS_NAME_STYLE).toString(),
new ReflectionToStringBuilder(bean2, ToStringStyle.NO_CLASS_NAME_STYLE).toString());
答案 2 :(得分:0)
如果您的实体具有公共属性,请使用抽象类并覆盖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;
}
答案 3 :(得分:0)
您可以使用反射作为解决问题的方法,但是最好的方法是使用@imperezivan所说的,使用共同祖先将属性放在同一位置。
反射实现就像获取每个对象的所有字段并比较其值一样容易。这里有一个例子:
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
如果您打算使用此代码,请测试边缘情况,因为我还没有这样做