Что лучший способ состоит в том, чтобы сравнить несколько javabean свойств?

Вероятно, вы можете оптимизировать кеш с помощью цикла SIMD, который читает, может быть, 8 или 12 полных векторов строк, а затем те же строки для следующего столбца. (То есть для 32-битных элементов, 8 * 4 или 8 * 8 строк параллельно). Вы используете MSVC, который поддерживает встроенные функции x86 SSE2 / AVX2, такие как _mm256_load_ps и _mm256_max_ps или _mm256_max_epi32.

Если вы начнете с границы выравнивания, то, надеюсь, вы прочитаете все строки кеша, к которым вы прикоснулись. И затем тот же шаблон доступа в выходных данных. (Таким образом, вы читаете от 2 до 6 последовательных строк кэша с шагом между блоками чтения / записи.)

Или, возможно, записать результаты tmp где-нибудь компактно (1 значение на сегмент в строке), прежде чем уничтожить больше кеш запись копий одного и того же элемента в каждый столбец. Но попробуйте оба пути; смешивание операций чтения и записи может позволить процессору лучше перекрывать работу и находить больше параллелизма на уровне памяти.

14
задан tputkonen 18 May 2009 в 05:33
поделиться

9 ответов

Используйте Аннотации .

Если вы отметите поля, которые вам нужно сравнить (независимо от того, являются ли они частными, вы все равно не потеряете инкапсуляцию и затем получите эти поля и сравните их. Это может быть следующее:

В классе, который нужно сравнить:

@ComparableField 
private String field1;

@ComparableField
private String field2;

private String field_nocomparable;

И во внешнем классе:

public <T> void compare(T t, T t2) throws IllegalArgumentException,
                                          IllegalAccessException {
    Field[] fields = t.getClass().getDeclaredFields();
    if (fields != null) {
        for (Field field : fields) {
            if (field.isAnnotationPresent(ComparableField.class)) {
                field.setAccessible(true);
                if ( (field.get(t)).equals(field.get(t2)) )
                    System.out.println("equals");
                field.setAccessible(false);
            }
        }
    }
}

Код не тестируется, но дайте мне знать, если поможет .

16
ответ дан 1 December 2019 в 12:02
поделиться

Это, вероятно, тоже не слишком хорошо, но это гораздо менее злобно (ИМХО), чем любая из двух предложенных вами альтернатив.

Как насчет предоставления одной пары геттер / сеттер, которая принимает поле числового индекса, а затем геттер / сеттер разыменовывает индексное поле на соответствующую переменную-член?

то есть:

public class MyClass {
    public void setMember(int index, String value) {
        switch (index) {
           ...
        }
    }

    public String getMember(int index) {
        ...
    }

    static public String getMemberName(int index) {
        ...
    }
}

А затем в вашем внешнем классе:

public void compareAndUpdate(MyClass a, MyClass b) {
    for (int i = 0; i < a.getMemberCount(); ++i) {
        String sa = a.getMember();
        String sb = b.getMember();
        if (!sa.equals(sb)) {
            Log.v("compare", a.getMemberName(i));
            b.setMember(i, sa);
        }
    }
}

Это, по крайней мере, позволяет вам сохранить все важные логика в исследуемом классе.

1
ответ дан 1 December 2019 в 12:02
поделиться

Я бы выбрал вариант 1, но я бы использовал getClass (). GetDeclaredFields () для доступа к полям вместо использования имен.

public void compareAndUpdate(MyClass other) throws IllegalAccessException {
    for (Field field : getClass().getDeclaredFields()) {
        if (field.getType() == String.class) {
            Object thisValue = field.get(this);
            Object otherValue = field.get(other);
            // if necessary check for null
            if (!thisValue.equals(otherValue)) {
                log(field.getName() + ": " + thisValue + " <> " + otherValue);
                field.set(other, thisValue);
            }
        }
    }
}

Есть некоторые здесь есть ограничения (если я прав):

  • Метод сравнения должен быть реализован в том же классе (на мой взгляд, должен - независимо от его реализации), а не во внешнем.
  • Только поля из этого используется класс, а не тот, который принадлежит суперклассу.
  • Требуется обработка исключения IllegalAccessException (я просто добавляю его в приведенном выше примере).
2
ответ дан 1 December 2019 в 12:02
поделиться

Общая мысль:

Создайте новый класс, объект которого принимает следующие параметры: первый класс для сравнения, второй класс для сравнения и списки имен методов получения и установки для объекты, в которые включены только интересующие методы.

Вы можете запросить с отражением класс объекта и оттуда его доступные методы. Предполагая, что каждый метод получения в списке параметров включен в доступные методы для класса, вы должны иметь возможность вызвать метод, чтобы получить значение для сравнения.

В общих чертах набросал что-то вроде (извиняюсь, если это не супер- идеально ... не мой основной язык):

public class MyComparator
{
    //NOTE: Class a is the one that will get the value if different
    //NOTE: getters and setters arrays must correspond exactly in this example
    public static void CompareMyStuff(Object a, Object b, String[] getters, String[] setters)
    {
        Class a_class = a.getClass();
        Class b_class = b.getClass();

        //the GetNamesFrom... static methods are defined elsewhere in this class
        String[] a_method_names = GetNamesFromMethods(a_class.getMethods());
        String[] b_method_names = GetNamesFromMethods(b_class.getMethods());
        String[] a_field_names = GetNamesFromFields(a_class.getFields());

        //for relative brevity...
        Class[] empty_class_arr = new Class[] {};
        Object[] empty_obj_arr = new Object[] {};

        for (int i = 0; i < getters.length; i++)
        {
            String getter_name = getter[i];
            String setter_name = setter[i];

            //NOTE: the ArrayContainsString static method defined elsewhere...
            //ensure all matches up well...
            if (ArrayContainsString(a_method_names, getter_name) &&
                ArrayContainsString(b_method_names, getter_name) &&
                ArrayContainsString(a_field_names, setter_name)
            {
                //get the values from the getter methods
                String val_a = a_class.getMethod(getter_name, empty_class_arr).invoke(a, empty_obj_arr);
                String val_b = b_class.getMethod(getter_name, empty_class_arr).invoke(b, empty_obj_arr);
                if (val_a != val_b)
                {
                    //LOG HERE
                    //set the value
                    a_class.getField(setter_name).set(a, val_b);
                }
            } 
            else
            {
                //do something here - bad names for getters and/or setters
            }
        }
    }
} 
0
ответ дан 1 December 2019 в 12:02
поделиться

While option 1 may be ugly, it will get the job done. Option 2 is even uglier, and opens your code to vulnerabilities you can't imagine. Even if you eventually rule out option 1, I pray you keep your existing code and not go for option 2.

Having said this, you can use reflection to get a list of the field names of the class, if you don't want to pass this as a static list to the method. Assuming you want to compare all fields, you can then dynamically create the comparisons, in a loop.

If this isn't the case, and the strings you compare are only some of the fields, you can examine the fields further and isolate only those that are of type String, and then proceed to compare.

Hope this helps,

Yuval =8-)

1
ответ дан 1 December 2019 в 12:02
поделиться

с

Все поля имеют тип String, и я могу изменить код класса, владеющего полями, если требуется.

вы можете попробовать этот класс:

public class BigEntity {

    private final Map<String, String> data;

    public LongEntity() {
        data = new HashMap<String, String>();
    }

    public String getFIELD1() {
        return data.get(FIELD1);
    }

    public String getFIELD2() {
        return data.get(FIELD2);
    }

    /* blah blah */
    public void cloneAndLogDiffs(BigEntity other) {
        for (String field : fields) {
            String a = this.get(field);
            String b = other.get(field);

            if (!a.equals(b)) {
                System.out.println("diff " + field);
                other.set(field, this.get(field));
            }
        }
    }

    private String get(String field) {
        String value = data.get(field);

        if (value == null) {
            value = "";
        }

        return value;
    }

    private void set(String field, String value) {
        data.put(field, value);
    }

    @Override
    public String toString() {
        return data.toString();
    }

магический код:

    private static final String FIELD1 = "field1";
    private static final String FIELD2 = "field2";
    private static final String FIELD3 = "field3";
    private static final String FIELD4 = "field4";
    private static final String FIELDN = "fieldN";
    private static final List<String> fields;

    static {
        fields = new LinkedList<String>();

        for (Field field : LongEntity.class.getDeclaredFields()) {
            if (field.getType() != String.class) {
                continue;
            }

            if (!Modifier.isStatic(field.getModifiers())) {
                continue;
            }

            fields.add(field.getName().toLowerCase());
        }
    }

этот класс имеет несколько преимуществ:

  • отражает один раз, при загрузке класса
  • он очень просто добавляет новые поля, просто добавляет новое статическое поле (лучшее решение здесь использует аннотации: в случае использования отражения работает также java 1.4)
  • , вы можете реорганизовать этот класс в абстрактный класс, все производные классы просто получают оба
    data и cloneAndLogDiffs ()
  • внешний интерфейс является типобезопасным (вы также можете легко наложить неизменяемость)
  • нет setAccessible вызовов: этот метод иногда проблематичен
1
ответ дан 1 December 2019 в 12:02
поделиться

Вы говорите, что у вас есть геттеры и сеттеры для всех этих полей? Хорошо, тогда измените базовые данные из группы отдельных полей в массив. Измените все геттеры и сеттеры для доступа к массиву. Я бы создал постоянные теги для индексов, а не использовал числа для долгосрочной поддержки. Также создайте параллельный массив флагов, указывающих, какие поля должны быть обработаны. Затем создайте общую пару геттер / сеттер, которая использует индекс, а также геттер для флага сравнения. Примерно так:

public class SomeClass
{
  final static int NUM_VALUES=3;
  final static int FOO=0, BAR=1, PLUGH=2;
  String[] values=new String[NUM_VALUES];
  static boolean[] wantCompared={true, false, true};

  public String getFoo()
  {
    return values[FOO];
  }
  public void setFoo(String foo)
  {
    values[FOO]=foo;
  }
  ... etc ...
  public int getValueCount()
  {
    return NUM_VALUES;
  }
  public String getValue(int x)
  {
    return values[x];
  }
  public void setValue(int x, String value)
  {
    values[x]=value;
  }
  public boolean getWantCompared(int x)
  {
    return wantCompared[x];
  }
}
public class CompareClass
{
  public void compare(SomeClass sc1, SomeClass sc2)
  {
    int z=sc1.getValueCount();
    for (int x=0;x<z;++x)
    {
      if (!sc1.getWantCompared[x])
        continue;
      String sc1Value=sc1.getValue(x);
      String sc2Value=sc2.getValue(x);
      if (!sc1Value.equals(sc2Value)
      {
        writeLog(x, sc1Value, sc2Value);
        sc2.setValue(x, sc1Value);
      }
    }
  }
}

Я просто придумал это, я не тестировал это, так что могут быть ошибки в коде, но я думаю, что концепция должна работать.

Поскольку у вас уже есть геттеры. и сеттеры, любой другой код, использующий этот класс, должен продолжать работать без изменений. Если нет другого кода, использующего этот класс,

0
ответ дан 1 December 2019 в 12:02
поделиться

API JavaBeans предназначен для помощи в самоанализе. В той или иной форме он существует со времен Java версии 1.

4
ответ дан 1 December 2019 в 12:02
поделиться

Я бы также предложил решение, аналогичное тому, которое было предложено Альнитаком.

Если при сравнении требуется итерация полей, почему бы не отказаться от отдельных полей и не поместить данные в массив, HashMap или что-то подобное.

Затем вы можете получить к ним доступ программно, сравнить их и т. д. Если разные поля нужно обрабатывать и сравнивать по-разному, вы можете создать соответствующие вспомогательные классы для значений, которые реализуют интерфейс.

Затем вы можете просто сделать

valueMap.get("myobject").compareAndChange(valueMap.get("myotherobject")

или что-то в этом роде ...

0
ответ дан 1 December 2019 в 12:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: