Сравнение значений полей с использованием отражения

Я пытаюсь сравнить значения полей двух разных объектов в общем виде. У меня есть функция (см. ниже), которая принимает два объекта, а затем получает поля, а затем сравнивает поля в цикле и добавляет поля в список, если они не совпадают - это правильный способ сделать это?

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();
 }
}

Я гуглил и увидел, что в С# есть класс PropertyInfo - есть ли что-нибудь подобное в Java? ТАКЖЕ, есть ли способ сделать как f.getFieldValue() - я знаю, что такого метода нет, но, может быть, есть другой способ???


person JonH    schedule 21.11.2012    source источник
comment
Поля принадлежат классам, значения хранятся (если не статичны) в экземплярах. Чего именно вы пытаетесь достичь?   -  person khachik    schedule 21.11.2012
comment
Хорошо, я должен был быть яснее - я передаю два экземпляра двух объектов - я пытаюсь сравнить два набора данных (списков объектов), которые возвращаются спящим режимом, - но я передаю их в цикле один экземпляр объекта некоторого класс за раз, чтобы сравнить поля этого экземпляра с каким-то другим экземпляром   -  person JonH    schedule 21.11.2012
comment
@JohH Если вы используете Hibernate, этот подход может не сработать — Hibernate изменяет содержимое объекта во время выполнения, и я не уверен, что отражение сработает — возможно, но если вы столкнетесь с чем-то забавным, это может быть связано с тем, что Hibernate мешает свойствам объекта .   -  person Ravi Wallau    schedule 21.11.2012
comment
@RaviWallau Я думаю, что в этот момент Hibernate перестал вмешиваться в эти объекты ... Я запускаю запрос, а затем получаю List‹Object›() обратно из hibernate. Если бы я хотел сделать это не общим способом, я мог бы привести каждый из экземпляров в списке, а затем сравнить значения, но это было бы много кода, который можно было бы сделать в общем.   -  person JonH    schedule 21.11.2012
comment
@JohH Если вы используете IntelliJ, вы можете автоматически генерировать equals() и hashCode(). Мне это нравится больше, чем использование отражения для сравнения данных, поскольку с отражением вы не можете ограничить поля, которые будут сравниваться.   -  person Ravi Wallau    schedule 22.11.2012
comment
Не по теме - я вижу, вы только что удалили вопрос. Я надеюсь, что вы не позволили негативу добраться до вас, это был правильный вопрос, и вы заслужили разумный ответ. stackoverflow.com/questions/13960118/64-bit-pointer-conversion< /а>   -  person Mark Ransom    schedule 20.12.2012
comment
@MarkRansom Я понял, что не полностью понял код до того, как задал вопрос, и как только я понял, я понял, что вопрос был не очень хорошим вопросом ... и поскольку он получил так много отзывов, что это лучше бы удалил...   -  person JonH    schedule 26.12.2012


Ответы (3)


Вы можете проверить org.apache.commons.lang.builder.EqualsBuilder, который избавит вас от многих хлопот, если вы хотите выполнить сравнение полей.

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

Если вы хотите сравнить поля самостоятельно, проверьте java.lang.Class.getDeclaredFields(), который предоставит вам все поля, включая поля, не являющиеся общедоступными.

Чтобы сравнить значения полей, используйте f.get(qa).equals(f.get(qa4)) В настоящее время вы фактически сравниваете экземпляры полей, а не значения.

person tjg184    schedule 21.11.2012
comment
как getDeclaredFields() помогает, когда мне нужно сравнить значения? - person JonH; 21.11.2012
comment
@JonH Я немного обновил свой ответ. Суть в том, что вам действительно следует рассмотреть общую библиотеку для проведения этого сравнения. Надеюсь это поможет. - person tjg184; 21.11.2012
comment
Хорошо, я считаю, что это работает, но у меня есть быстрый вопрос: так of.get(qa) получит значение поля some_name, поэтому мне не нужно беспокоиться о порядке полей или убедиться, что оно сравнивает одно и то же поле, верно? - person JonH; 21.11.2012
comment
Предполагая, что это один и тот же тип класса, порядок полей будет таким же. - person tjg184; 21.11.2012

Библиотеки, такие как commons-beanutils, могут помочь вам, если вместо этого вы хотите сравнить свойства компонентов (значения, возвращаемые геттерами). сравнения значений полей.

Однако, если вы хотите придерживаться простого отражения, вам следует:

  1. Используйте Class.getDeclaredFields() вместо Class.getFields(), так как последний возвращает только общедоступные поля.
  2. Поскольку поля зависят только от их класса, вы должны кэшировать результат и хранить поля в статической переменной/переменной экземпляра, а не вызывать getDeclaredFields() для каждого сравнения.
  3. Если у вас есть объект этого класса (скажем, o), чтобы получить значение некоторого поля f для этого конкретного объекта, вам нужно вызвать: f.get(o).
person Costi Ciudatu    schedule 21.11.2012

// Если вы хотите иметь некоторые поля, а не все поля, используйте это.

  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;
}
person Ahmed Ali    schedule 30.10.2018