Comparing field values using reflection

2019-02-17 21:04发布

问题:

I am trying to compare the field values of two different objects in a generic way. I have a function (seen below) that takes in two Objects and then gets the fields and then compares the fields in a loop and adds the fields to a list if they are not the same - is this the proper way to do this?

public void compareFields(Object qa, Object qa4) throws FieldsNotEqualException
{

  Field[] qaFields = qa.getClass().getFields();
  Field[] qa4Fields = qa4.getClass().getFields();

  for(Field f:qaFields) 
  { 

    for(Field f4:qa4Fields)
    {
       if(f4.equals(f))
       {
           found = true;
           break;
       }
       else
       {
           continue;
       }
    }
  }

 if(!found)
 {
    report.add(/*some_formatted_string*/) //some global list 
    throw new FieldsNotEqualException();
 }
}

I was googling and I saw that C# had like a PropertyInfo Class - does Java have anything like that? ALSO, is there a way to do like f.getFieldValue() -I know there is no method like this but maybe there is another way???

回答1:

You might check out org.apache.commons.lang.builder.EqualsBuilder which will save you a lot of this hassle if you're wanting to do a field by field comparison.

org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(Object, Object)

If you're wanting to compare fields yourself, check out java.lang.Class.getDeclaredFields() which will give you all the fields including non-public fields.

To compare the value of the fields use f.get(qa).equals(f.get(qa4)) Currently, you are actually comparing the field instances and not the values.



回答2:

Libraries like commons-beanutils can help you if you want to compare bean properties (values returned by getters) instead of comparing field values.

However, if you want to stick with plain reflection, you should:

  1. Use Class.getDeclaredFields() instead of Class.getFields(), as the latter only returns the public fields.
  2. Since fields only depend on their class, you should cache the result and keep the fields in a static / instance variable rather than invoking getDeclaredFields() for each comparison.
  3. Once you have an object of that class (say o), in order to get the value of some field f for that particular object, you need to call: f.get(o).


回答3:

// If you want to have some fields, not all field then use this.

  public boolean compareObject(Object object) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 
{

 String[] compareFields = { "fieldx", "fieldy","fieldz", "field15",
        "field19"}; // list of all we need 
for(String s : compareFields) {
Field field = DcrAttribute.class.getDeclaredField(s); // get a list of all fields for this class
    field.setAccessible(true);
    if(!field.get(this).equals(field.get(object))){  //if values are not equal          
    return true;    
    }       

    }

    return false;
}